diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 8d271630..b76125d7 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -9,7 +9,7 @@ { "name": "agent-portability-skills", "source": "./plugins/agent-portability-skills", "description": "Cross-host agent-skill and plugin portability workflows.", "category": "developer-tools", "tags": ["skills", "portability"], "strict": false }, { "name": "android-dev-skills", "source": "./plugins/android-dev-skills", "description": "Android, Kotlin, Java, Gradle, testing, and release workflows.", "category": "developer-tools", "tags": ["android", "skills"], "strict": false }, { "name": "apple-creator-studio-skills", "source": "./plugins/apple-creator-studio-skills", "description": "Apple Creator Studio workflows for production and delivery.", "category": "productivity", "tags": ["apple", "creative"], "strict": false }, - { "name": "apple-dev-skills", "source": "./plugins/apple-dev-skills", "description": "Apple, SwiftPM, Xcode, and macOS or Linux virtualization workflows.", "category": "developer-tools", "tags": ["apple", "swift", "swiftpm", "xcode", "virtualization"], "mcpServers": "./.mcp.json", "strict": false }, + { "name": "apple-dev-skills", "source": "./plugins/apple-dev-skills", "description": "Apple, SwiftPM, Xcode, macOS privacy, file access, entitlement, and virtualization workflows.", "category": "developer-tools", "tags": ["apple", "swift", "swiftpm", "xcode", "macos", "privacy", "entitlements", "virtualization"], "mcpServers": "./.mcp.json", "strict": false }, { "name": "cardhop-app", "source": "./plugins/cardhop-app", "description": "Cardhop contact workflows with a Claude Code local MCP server.", "category": "productivity", "tags": ["contacts", "macos", "local-mcp"], "mcpServers": "./claude.mcp.json", "strict": false }, { "name": "cloud-deployment-skills", "source": "./plugins/cloud-deployment-skills", "description": "Cloud deployment routing and provider integration workflows.", "category": "developer-tools", "tags": ["cloud", "deployment"], "strict": false }, { "name": "cloud-inference-skills", "source": "./plugins/cloud-inference-skills", "description": "Cloud AI inference, training, conversion, and GPU workflows.", "category": "developer-tools", "tags": ["ai", "cloud", "mcp"], "mcpServers": "./.mcp.json", "strict": false }, @@ -21,7 +21,7 @@ { "name": "network-protocol-skills", "source": "./plugins/network-protocol-skills", "description": "Networking, transport, QUIC, HTTP/3, and WebRTC workflows.", "category": "developer-tools", "tags": ["networking", "protocols"], "strict": false }, { "name": "productivity-skills", "source": "./plugins/productivity-skills", "description": "Maintainer, documentation, job-search, and automation-design workflows.", "category": "productivity", "tags": ["maintenance", "automation", "mcp"], "mcpServers": "./.mcp.json", "strict": false }, { "name": "python-skills", "source": "./plugins/python-skills", "description": "Python, uv, FastAPI, FastMCP, testing, and packaging workflows.", "category": "developer-tools", "tags": ["python", "uv"], "strict": false }, - { "name": "reverse-engineering-skills", "source": "./plugins/reverse-engineering-skills", "description": "Artifact triage, binary analysis, and reproducible evidence workflows.", "category": "developer-tools", "tags": ["reverse-engineering", "security"], "strict": false }, + { "name": "reverse-engineering-skills", "source": "./plugins/reverse-engineering-skills", "description": "Artifact triage, binary analysis, exact-build macOS control research, and reproducible evidence workflows.", "category": "developer-tools", "tags": ["reverse-engineering", "security", "macos", "forensics"], "strict": false }, { "name": "rust-skills", "source": "./plugins/rust-skills", "description": "Rust, Cargo, crate, test, CI, and package workflows.", "category": "developer-tools", "tags": ["rust", "cargo"], "strict": false }, { "name": "server-side-jvm", "source": "./plugins/server-side-jvm", "description": "Java, Scala, JVM service, build, and testing workflows.", "category": "developer-tools", "tags": ["java", "scala", "jvm"], "strict": false }, { "name": "server-side-swift", "source": "./plugins/server-side-swift", "description": "Vapor, Hummingbird, SwiftNIO, Docker, and Apple container workflows.", "category": "developer-tools", "tags": ["swift", "server", "containers"], "strict": false }, diff --git a/ROADMAP.md b/ROADMAP.md index 0103748a..453d85e9 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -31,6 +31,7 @@ - [Milestone 28: Swift language tooling expansion](#milestone-28-swift-language-tooling-expansion) - [Milestone 29: Model Lab skills plugin](#milestone-29-model-lab-skills-plugin) - [Milestone 30: macOS virtualization and container skills expansion](#milestone-30-macos-virtualization-and-container-skills-expansion) +- [Milestone 31: macOS platform security skills expansion](#milestone-31-macos-platform-security-skills-expansion) - [Small Tickets](#small-tickets) - [Backlog Candidates](#backlog-candidates) - [History](#history) @@ -75,6 +76,7 @@ - Milestone 28: Swift language tooling expansion - In Progress - Milestone 29: Model Lab skills plugin - Planned - Milestone 30: macOS virtualization and container skills expansion - Completed +- Milestone 31: macOS platform security skills expansion - Completed ## Milestone 5: SwiftASB skills plugin @@ -1033,6 +1035,39 @@ Completed Completed Milestone 30 by shipping four Apple Dev virtualization workflows, a disposable Cybersecurity lab-preparation workflow, Apple `container` 1.x and `container machine` guidance, guest-versus-host evidence rules, Hermes exports, Claude and Cowork compatibility metadata, architecture inventory updates, and ten scenario-level forward tests. The rebased `9.19.0` release candidate preserves the concurrent Model Lab inventory and passed 268 Apple Dev tests, 126 Socket tests with one intentional skip, Apple and Cybersecurity child validators, Socket marketplace validation, Hermes parity, Claude/Cowork validation, and the architecture consistency check. +## Milestone 31: macOS platform security skills expansion + +### Status + +Completed + +### Scope + +- [x] Record the source baseline, ownership, control-layer model, evidence record, skill contracts, fixtures, compatibility, validation, and implementation slices in [`docs/maintainers/macos-platform-security-skills-plan.md`](./docs/maintainers/macos-platform-security-skills-plan.md). +- [x] Add three Apple Dev workflows for privacy permissions, sandboxed file access, and entitlement diagnosis without creating a duplicate macOS security plugin. +- [x] Add one Reverse Engineering workflow for exact-build public/private macOS security-control research and technical notes. +- [x] Align existing Cybersecurity macOS workflows around explicit developer, research, threat-assessment, and isolation handoffs without moving defensive ownership. +- [x] Keep the first implementation instruction-only: no TCC database mutation, permission grant service, privileged helper, daemon, endpoint agent, MCP server, protection bypass, or live-host prompt automation. + +### Planned Slices + +- [x] Slice 1: ship `apple-dev-skills:macos-privacy-permissions-workflow` with responsible-code attribution, public API, prompt/settings, reset-only, PPPC, and disposable-fixture contracts. +- [x] Slice 2: ship `apple-dev-skills:macos-sandbox-file-access-workflow` and `apple-dev-skills:diagnose-apple-entitlements`, then align provisioning, distribution, extension, File Provider, and Xcode handoffs. +- [x] Slice 3: ship `reverse-engineering-skills:research-macos-security-control`, connect exact-build research and technical notes to existing artifact/signing/dynamic-analysis workflows, and align Cybersecurity handoffs. +- [x] Slice 4: forward-test the complete scenario matrix, remediate trigger and handoff gaps, update discovery metadata and user-facing inventory, export portable skills through Hermes, record Claude/Cowork compatibility, and run full affected validation. +- [x] Reconsider a standalone `macos-security-skills` plugin or shared read-only diagnostic collector only after repeated implementation use satisfies the explicit gate in the maintainer plan; retain the focused existing owners for this release. + +### Exit Criteria + +- [x] Agents identify the responsible executable and controlling security layer before suggesting a permission, entitlement, signing, distribution, malware, or system-policy change. +- [x] Public application guidance never treats private TCC symbols, direct database access, `tccutil reset`, an entitlement, or administrator privileges as a supported permission grant. +- [x] File-access guidance preserves the complete security-scoped bookmark lifecycle and distinguishes App Sandbox, TCC, POSIX/ACL, Data Vault, and SIP failures. +- [x] Entitlement guidance compares requested behavior, tracked source, account/profile authorization, final signed code, and runtime authorization for every affected target. +- [x] Private-control research records exact builds and clearly separates public contract, private implementation evidence, runtime observation, inference, and transformed artifacts. +- [x] Apple Dev, Reverse Engineering, Cybersecurity, Socket, Hermes, and Claude/Cowork discovery and validation surfaces agree on the shipped owner boundaries. + +Completed Milestone 31 by shipping four focused, instruction-only macOS platform-security workflows across Apple Dev and Reverse Engineering Skills, aligning defensive Cybersecurity handoffs, preserving visible prompt and protection-state approval gates, exporting the portable skill set through Hermes, and recording Claude Code/Cowork compatibility without introducing a permission manager, privileged service, or duplicate plugin. + ## Small Tickets - [ ] Record issue-sized fixes, TODO/FIXME imports, and cleanup work that is too small or too unplanned for a milestone. diff --git a/docs/architecture/ARCHITECTURE.md b/docs/architecture/ARCHITECTURE.md index 5d0b26ad..cbfda7d7 100644 --- a/docs/architecture/ARCHITECTURE.md +++ b/docs/architecture/ARCHITECTURE.md @@ -82,6 +82,7 @@ See [SLICES.md](./SLICES.md) for provable end-to-end code paths. - `skill:apple-dev-skills/coreaudio-modernization-repair-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/coreaudio-modernization-repair-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/coremedia-timing-samplebuffer-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/coremedia-timing-samplebuffer-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/devicecheck-app-attest-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/SKILL.md` depends on: no declared dependencies. +- `skill:apple-dev-skills/diagnose-apple-entitlements` (codex-skill) at `plugins/apple-dev-skills/skills/diagnose-apple-entitlements/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/explore-apple-swift-docs` (codex-skill) at `plugins/apple-dev-skills/skills/explore-apple-swift-docs/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/feedback-assistant-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/feedback-assistant-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/file-provider-and-finder-sync-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/file-provider-and-finder-sync-workflow/SKILL.md` depends on: no declared dependencies. @@ -91,11 +92,14 @@ See [SLICES.md](./SLICES.md) for provable end-to-end code paths. - `skill:apple-dev-skills/linux-development-vm-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/linux-development-vm-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/macos-development-vm-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/macos-development-vm-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/macos-distribution-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/macos-distribution-workflow/SKILL.md` depends on: no declared dependencies. +- `skill:apple-dev-skills/macos-privacy-permissions-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/SKILL.md` depends on: no declared dependencies. +- `skill:apple-dev-skills/macos-sandbox-file-access-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/macos-window-management-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/macos-window-management-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/mailkit-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/mailkit-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/migrate-xcode-project-to-xcodegen` (codex-skill) at `plugins/apple-dev-skills/skills/migrate-xcode-project-to-xcodegen/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/photos-library-editing-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/photos-library-editing-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/safari-extension-control-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md` depends on: no declared dependencies. +- `skill:apple-dev-skills/safari-mcp-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/safari-mcp-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/sf-symbols-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/sf-symbols-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/structure-swift-sources` (codex-skill) at `plugins/apple-dev-skills/skills/structure-swift-sources/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/swift-openapi-client-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/swift-openapi-client-workflow/SKILL.md` depends on: no declared dependencies. @@ -265,6 +269,7 @@ See [SLICES.md](./SLICES.md) for provable end-to-end code paths. - `skill:reverse-engineering-skills/recover-apple-runtime-metadata` (codex-skill) at `plugins/reverse-engineering-skills/skills/recover-apple-runtime-metadata/SKILL.md` depends on: no declared dependencies. - `skill:reverse-engineering-skills/report-apple-security-research` (codex-skill) at `plugins/reverse-engineering-skills/skills/report-apple-security-research/SKILL.md` depends on: no declared dependencies. - `skill:reverse-engineering-skills/research-apple-kernel-boot-and-firmware` (codex-skill) at `plugins/reverse-engineering-skills/skills/research-apple-kernel-boot-and-firmware/SKILL.md` depends on: no declared dependencies. +- `skill:reverse-engineering-skills/research-macos-security-control` (codex-skill) at `plugins/reverse-engineering-skills/skills/research-macos-security-control/SKILL.md` depends on: no declared dependencies. - `skill:reverse-engineering-skills/review-decompiler-output` (codex-skill) at `plugins/reverse-engineering-skills/skills/review-decompiler-output/SKILL.md` depends on: no declared dependencies. - `skill:reverse-engineering-skills/script-hopper-analysis` (codex-skill) at `plugins/reverse-engineering-skills/skills/script-hopper-analysis/SKILL.md` depends on: no declared dependencies. - `skill:reverse-engineering-skills/select-analysis-path` (codex-skill) at `plugins/reverse-engineering-skills/skills/select-analysis-path/SKILL.md` depends on: no declared dependencies. @@ -378,6 +383,7 @@ The structured visual model lives in [architecture.json](./architecture.json). I - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/coreaudio-modernization-repair-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/coremedia-timing-samplebuffer-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/SKILL.md`. +- `skill-manifest` evidence from `plugins/apple-dev-skills/skills/diagnose-apple-entitlements/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/explore-apple-swift-docs/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/feedback-assistant-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/file-provider-and-finder-sync-workflow/SKILL.md`. @@ -387,11 +393,14 @@ The structured visual model lives in [architecture.json](./architecture.json). I - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/linux-development-vm-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/macos-development-vm-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/macos-distribution-workflow/SKILL.md`. +- `skill-manifest` evidence from `plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/SKILL.md`. +- `skill-manifest` evidence from `plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/macos-window-management-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/mailkit-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/migrate-xcode-project-to-xcodegen/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/photos-library-editing-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md`. +- `skill-manifest` evidence from `plugins/apple-dev-skills/skills/safari-mcp-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/sf-symbols-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/structure-swift-sources/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/swift-openapi-client-workflow/SKILL.md`. @@ -573,6 +582,7 @@ The structured visual model lives in [architecture.json](./architecture.json). I - `skill-manifest` evidence from `plugins/reverse-engineering-skills/skills/recover-apple-runtime-metadata/SKILL.md`. - `skill-manifest` evidence from `plugins/reverse-engineering-skills/skills/report-apple-security-research/SKILL.md`. - `skill-manifest` evidence from `plugins/reverse-engineering-skills/skills/research-apple-kernel-boot-and-firmware/SKILL.md`. +- `skill-manifest` evidence from `plugins/reverse-engineering-skills/skills/research-macos-security-control/SKILL.md`. - `skill-manifest` evidence from `plugins/reverse-engineering-skills/skills/review-decompiler-output/SKILL.md`. - `skill-manifest` evidence from `plugins/reverse-engineering-skills/skills/script-hopper-analysis/SKILL.md`. - `skill-manifest` evidence from `plugins/reverse-engineering-skills/skills/select-analysis-path/SKILL.md`. diff --git a/docs/architecture/architecture.json b/docs/architecture/architecture.json index cd87ba43..e7cfc75c 100644 --- a/docs/architecture/architecture.json +++ b/docs/architecture/architecture.json @@ -1,5 +1,5 @@ { - "detectedAt": "2026-07-19T17:41:35.923846+00:00", + "detectedAt": "2026-07-19T19:27:23.828783+00:00", "detectionSource": "plugin-repo", "evidence": [ { @@ -170,6 +170,10 @@ "kind": "skill-manifest", "path": "plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/SKILL.md" }, + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/diagnose-apple-entitlements/SKILL.md" + }, { "kind": "skill-manifest", "path": "plugins/apple-dev-skills/skills/explore-apple-swift-docs/SKILL.md" @@ -206,6 +210,14 @@ "kind": "skill-manifest", "path": "plugins/apple-dev-skills/skills/macos-distribution-workflow/SKILL.md" }, + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/SKILL.md" + }, + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/SKILL.md" + }, { "kind": "skill-manifest", "path": "plugins/apple-dev-skills/skills/macos-window-management-workflow/SKILL.md" @@ -226,6 +238,10 @@ "kind": "skill-manifest", "path": "plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md" }, + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/safari-mcp-workflow/SKILL.md" + }, { "kind": "skill-manifest", "path": "plugins/apple-dev-skills/skills/sf-symbols-workflow/SKILL.md" @@ -950,6 +966,10 @@ "kind": "skill-manifest", "path": "plugins/reverse-engineering-skills/skills/research-apple-kernel-boot-and-firmware/SKILL.md" }, + { + "kind": "skill-manifest", + "path": "plugins/reverse-engineering-skills/skills/research-macos-security-control/SKILL.md" + }, { "kind": "skill-manifest", "path": "plugins/reverse-engineering-skills/skills/review-decompiler-output/SKILL.md" @@ -2078,6 +2098,18 @@ "label": "plugin exposes skill", "to": "target:skill:apple-dev-skills/devicecheck-app-attest-workflow" }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/apple-dev-skills/skills/diagnose-apple-entitlements/SKILL.md" + } + ], + "from": "product:apple-dev-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:apple-dev-skills/diagnose-apple-entitlements" + }, { "evidence": [ { @@ -2186,6 +2218,30 @@ "label": "plugin exposes skill", "to": "target:skill:apple-dev-skills/macos-distribution-workflow" }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/SKILL.md" + } + ], + "from": "product:apple-dev-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:apple-dev-skills/macos-privacy-permissions-workflow" + }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/SKILL.md" + } + ], + "from": "product:apple-dev-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:apple-dev-skills/macos-sandbox-file-access-workflow" + }, { "evidence": [ { @@ -2246,6 +2302,18 @@ "label": "plugin exposes skill", "to": "target:skill:apple-dev-skills/safari-extension-control-workflow" }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/apple-dev-skills/skills/safari-mcp-workflow/SKILL.md" + } + ], + "from": "product:apple-dev-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:apple-dev-skills/safari-mcp-workflow" + }, { "evidence": [ { @@ -4274,6 +4342,18 @@ "label": "plugin exposes skill", "to": "target:skill:reverse-engineering-skills/research-apple-kernel-boot-and-firmware" }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/reverse-engineering-skills/skills/research-macos-security-control/SKILL.md" + } + ], + "from": "product:reverse-engineering-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:reverse-engineering-skills/research-macos-security-control" + }, { "evidence": [ { @@ -6018,6 +6098,18 @@ "name": "skill:apple-dev-skills/devicecheck-app-attest-workflow", "path": "plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/SKILL.md" }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/diagnose-apple-entitlements/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:apple-dev-skills/diagnose-apple-entitlements", + "path": "plugins/apple-dev-skills/skills/diagnose-apple-entitlements/SKILL.md" + }, { "dependencies": [], "evidence": [ @@ -6126,6 +6218,30 @@ "name": "skill:apple-dev-skills/macos-distribution-workflow", "path": "plugins/apple-dev-skills/skills/macos-distribution-workflow/SKILL.md" }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:apple-dev-skills/macos-privacy-permissions-workflow", + "path": "plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/SKILL.md" + }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:apple-dev-skills/macos-sandbox-file-access-workflow", + "path": "plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/SKILL.md" + }, { "dependencies": [], "evidence": [ @@ -6186,6 +6302,18 @@ "name": "skill:apple-dev-skills/safari-extension-control-workflow", "path": "plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md" }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/safari-mcp-workflow/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:apple-dev-skills/safari-mcp-workflow", + "path": "plugins/apple-dev-skills/skills/safari-mcp-workflow/SKILL.md" + }, { "dependencies": [], "evidence": [ @@ -8214,6 +8342,18 @@ "name": "skill:reverse-engineering-skills/research-apple-kernel-boot-and-firmware", "path": "plugins/reverse-engineering-skills/skills/research-apple-kernel-boot-and-firmware/SKILL.md" }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/reverse-engineering-skills/skills/research-macos-security-control/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:reverse-engineering-skills/research-macos-security-control", + "path": "plugins/reverse-engineering-skills/skills/research-macos-security-control/SKILL.md" + }, { "dependencies": [], "evidence": [ diff --git a/docs/maintainers/claude-compatibility.json b/docs/maintainers/claude-compatibility.json index adc988ba..08aee164 100644 --- a/docs/maintainers/claude-compatibility.json +++ b/docs/maintainers/claude-compatibility.json @@ -6,7 +6,7 @@ "agentdeck": { "claudeCode": "not_supported", "cowork": "not_supported", "note": "Codex thread-title hooks have no Claude equivalent." }, "android-dev-skills": { "claudeCode": "supported", "cowork": "skills_only", "note": "Instruction-only workflows." }, "apple-creator-studio-skills": { "claudeCode": "supported", "cowork": "skills_only", "note": "Instruction-only workflows." }, - "apple-dev-skills": { "claudeCode": "local_mcp", "cowork": "skills_only", "note": "Virtualization guidance is portable; the Xcode bridge and VM execution require the local Mac and Xcode." }, + "apple-dev-skills": { "claudeCode": "local_mcp", "cowork": "skills_only", "note": "Privacy, sandbox file-access, entitlement, and virtualization guidance is portable; Xcode bridges, visible permission actions, and VM execution require an approved local Mac context." }, "cardhop-app": { "claudeCode": "local_mcp", "cowork": "skills_only", "note": "Cardhop server runs on the local Mac." }, "cloud-deployment-skills": { "claudeCode": "supported", "cowork": "skills_only", "note": "Instruction-only workflows." }, "cloud-inference-skills": { "claudeCode": "remote_mcp", "cowork": "remote_mcp", "note": "Runpod endpoints are public remote MCP services; authentication remains operator-managed." }, @@ -18,7 +18,7 @@ "network-protocol-skills": { "claudeCode": "supported", "cowork": "skills_only", "note": "Instruction-only workflows." }, "productivity-skills": { "claudeCode": "remote_mcp", "cowork": "remote_mcp", "note": "Dice is a public remote MCP server." }, "python-skills": { "claudeCode": "supported", "cowork": "skills_only", "note": "Instruction-only workflows." }, - "reverse-engineering-skills": { "claudeCode": "supported", "cowork": "skills_only", "note": "Instruction-only workflows." }, + "reverse-engineering-skills": { "claudeCode": "supported", "cowork": "skills_only", "note": "Instruction-only workflows, including exact-build macOS control research; local artifacts and active probes remain operator-provided and approval-gated." }, "rust-skills": { "claudeCode": "supported", "cowork": "skills_only", "note": "Instruction-only workflows." }, "server-side-jvm": { "claudeCode": "supported", "cowork": "skills_only", "note": "Instruction-only workflows." }, "server-side-swift": { "claudeCode": "supported", "cowork": "skills_only", "note": "Instruction-only workflows; Apple container execution requires a supported local Mac." }, diff --git a/docs/maintainers/claude-compatibility.md b/docs/maintainers/claude-compatibility.md index 83a78e24..d36289d4 100644 --- a/docs/maintainers/claude-compatibility.md +++ b/docs/maintainers/claude-compatibility.md @@ -32,6 +32,8 @@ complete, machine-checked classification is in Its optional Python helpers read and write operator-selected local artifacts; the plugin declares no MCP server or host-specific runtime extension. +The macOS platform-security workflows remain instruction-portable in Claude Code and Cowork. Apple Dev Skills owns supported app permission, sandbox file-access, and entitlement diagnosis; Reverse Engineering Skills owns exact-build private-control research; Cybersecurity Skills owns defensive host investigation. Visible permission prompts, System Settings changes, local artifact inspection, VM execution, and protection-state changes still require the corresponding approved local environment and are not supplied by the Claude marketplace adapter. + `agentdeck` is intentionally absent from the Claude marketplace: its title hook is a Codex runtime integration, not an instruction workflow. `spotify` is also absent because it remains a Socket placeholder. `speak-swiftly` is diff --git a/docs/maintainers/hermes-compatibility.md b/docs/maintainers/hermes-compatibility.md index c203f28e..8ece07c1 100644 --- a/docs/maintainers/hermes-compatibility.md +++ b/docs/maintainers/hermes-compatibility.md @@ -29,9 +29,13 @@ Socket tap. The curated set is: - `hermes-agent-compatibility` - `sync-skills-repo-guidance` - `app-extension-architecture-workflow` +- `diagnose-apple-entitlements` - `mailkit-workflow` - `file-provider-and-finder-sync-workflow` +- `macos-privacy-permissions-workflow` +- `macos-sandbox-file-access-workflow` - `connect-hopper-mcp` +- `research-macos-security-control` - `script-hopper-analysis` - `use-ghidra` - `use-hopper` @@ -101,6 +105,8 @@ It resolves operator-installed Swiftly and Xcode tools and plans SwiftPM plugin, macro, trait, generated-source, and permission work without bundling a compiler, plugin runtime, MCP server, or native Hermes extension. +The exported macOS platform-security workflows are portable instruction contracts. Public app permission, sandbox file-access, and entitlement diagnosis remain in Apple Dev Skills; exact-build private-control research remains in Reverse Engineering Skills; defensive host investigation remains in Cybersecurity Skills. Hermes does not receive a TCC database tool, permission grant service, privileged helper, protection bypass, or native runtime plugin from this work. + ## Maintainer Workflow 1. Classify each changed surface before editing: portable skill, translated MCP, diff --git a/docs/maintainers/macos-platform-security-skills-plan.md b/docs/maintainers/macos-platform-security-skills-plan.md new file mode 100644 index 00000000..062d032e --- /dev/null +++ b/docs/maintainers/macos-platform-security-skills-plan.md @@ -0,0 +1,787 @@ +# macOS Platform Security Skills Plan + +## Intent + +Expand Socket's macOS security guidance so an agent can diagnose, implement, +research, and explain the platform controls that commonly get flattened into +one vague permission problem: + +- Transparency, Consent, and Control (TCC) privacy decisions +- Accessibility, Automation, Developer Tools, screen capture, input, media, + personal-data, and filesystem permission classes +- App Sandbox containers, user-selected files, security-scoped bookmarks, App + Groups, and other supported file-access paths +- capabilities, source entitlements, provisioning authorization, signed + entitlements, restricted entitlements, and runtime consent +- quarantine, Gatekeeper, notarization, XProtect, Execution Policy, Hardened + Runtime, System Integrity Protection (SIP), signed system volume protections, + Data Vaults, and related mandatory access controls +- exact-build technical notes for public APIs, private symbols, runtime evidence, + and changes between macOS releases + +The practical result should be an agent that identifies the real controlling +layer and responsible executable before suggesting a permission change. It +should be able to explain why granting Terminal does not necessarily authorize +Codex, Xcode, a helper, an XPC service, or the built application; why an +entitlement is not user consent; and why a bookmark, Full Disk Access, +Gatekeeper assessment, XProtect detection, App Sandbox denial, and SIP denial +are different facts. + +This is a coordinated expansion of existing Socket plugins. It does not create +a new catch-all macOS security plugin, modify the live TCC database, bundle a +privileged helper, install endpoint tooling, or automate changes to system +protections. + +## Source Baseline + +This plan was checked on 2026-07-19 against current local and Apple-owned +sources. Implementation must repeat the docs check because permission classes, +framework APIs, System Settings wording, and Endpoint Security events are +version-sensitive. + +- [Apple Platform Security](https://support.apple.com/guide/security/welcome/web) + separates system integrity, application trust, malware protection, user-data + controls, and encryption rather than presenting one universal permission + system. +- [Controlling app access to files in macOS](https://support.apple.com/guide/security/secddd1d86a6/web) + documents user consent for protected locations, Full Disk Access, + Accessibility, and Automation. +- [Privacy Preferences Policy Control](https://support.apple.com/guide/deployment/privacy-preferences-policy-control-payload-dep38df53c2a/web) + documents the managed-device PPPC payload, supported service classes, + designated-requirement identity, and TCC attribution logging. +- [Protecting user data with App Sandbox](https://developer.apple.com/documentation/security/protecting-user-data-with-app-sandbox) + and [Accessing files from the macOS App Sandbox](https://developer.apple.com/documentation/security/accessing-files-from-the-macos-app-sandbox) + document containers, user-selected access, bookmarks, and the limits imposed + by other discretionary and mandatory access controls. +- [Entitlements](https://developer.apple.com/documentation/bundleresources/entitlements) + and [Diagnosing Issues with Entitlements](https://developer.apple.com/documentation/bundleresources/diagnosing-issues-with-entitlements) + establish that source configuration, provisioning authorization, final + signed entitlements, and runtime behavior require separate evidence. +- [Configuring the Hardened Runtime](https://developer.apple.com/documentation/xcode/configuring-the-hardened-runtime/) + documents runtime hardening and narrowly scoped exception entitlements. +- [Gatekeeper and runtime protection in macOS](https://support.apple.com/guide/security/sec5599b66df/web) + documents download provenance, signing, notarization, first-open approval, + assessment, and randomized read-only launch behavior. +- [Protecting against malware in macOS](https://support.apple.com/guide/security/sec469d47bd8/web) + distinguishes prevention, execution blocking, and remediation and documents + Gatekeeper-bypass and XProtect Endpoint Security events on supported macOS + releases. +- [System Integrity Protection](https://support.apple.com/guide/security/secb7ea06b49/web) + documents SIP as a system-wide mandatory policy that is distinct from App + Sandbox, TCC, and administrative privileges. + +Local planning evidence on macOS 26.5.2 build 25F84 with the selected stable +Xcode SDK includes: + +- public `EPDeveloperTool.authorizationStatus` and `requestAccess()` in the + Execution Policy framework for the Developer Tools privacy class +- public `AXIsProcessTrustedWithOptions` for Accessibility trust +- public `AEDeterminePermissionToAutomateTarget` for Apple Events automation +- public `CGPreflightScreenCaptureAccess` and `CGRequestScreenCaptureAccess` + for screen capture +- framework-specific authorization APIs for camera, microphone, Contacts, + EventKit, Photos, location, and other protected data +- `tccutil` supporting reset, not a general supported grant or status API +- `syspolicy_check distribution` combining Gatekeeper, XProtect, + provisioning-profile, and related distribution checks +- `spctl` retaining assessment operations while macOS 15 and later deprecate + rule-database and global-state mutation operations in favor of supported + management policy + +These observations are a planning baseline, not portable truth. Each workflow +must discover the current OS build, SDK, responsible process, public API, and +tool behavior before making a version-sensitive claim. + +## Architecture Decision + +Extend `apple-dev-skills`, `reverse-engineering-skills`, and the existing macOS +workflows in `cybersecurity-skills` through explicit handoffs. Do not create a +fourth plugin that claims ownership of all macOS privacy and security systems. + +This is a durable building-block change. It unlocks these near-term uses: + +- diagnose why an app, command-line tool, agent host, helper, or XPC service is + missing Accessibility, Automation, Developer Tools, screen-capture, input, + personal-data, or filesystem access +- implement the documented preflight, request, explanation, denial, settings, + and retry lifecycle for permission classes that expose public APIs +- persist user-selected file access correctly across relaunches without + treating bookmarks as blanket storage permission +- trace an entitlement from desired capability through Xcode, the developer + account and profile, the signed executable, nested code, and observed runtime + authorization +- distinguish a developer configuration failure from a suspicious-host or + malware investigation +- create reproducible technical notes about public and private macOS security + controls without turning private symbols into supported application APIs +- compare behavior across clean macOS guests while keeping SIP-, recoveryOS-, + hardware-, and physical-Mac-only proof requirements explicit + +The simpler extension path was one `macos-security-workflow` skill or a new +`macos-security-skills` plugin. That would mix application implementation, +managed-device policy, malware investigation, binary inspection, private +framework research, and boot-level integrity controls. It would duplicate the +current plugins' legitimate ownership and make triggering less precise. The +focused skills below share an evidence vocabulary while retaining their own +entry conditions and outputs. + +No new runtime abstraction is approved in the first implementation. A shared +read-only diagnostic collector may be reconsidered only after repeated manual +captures prove a stable command and output contract that materially reduces +duplication. + +## Ownership And Handoffs + +| Surface | Primary owner | Responsibility | +| --- | --- | --- | +| App-facing privacy permission diagnosis and implementation | `apple-dev-skills:macos-privacy-permissions-workflow` | Classify the permission, responsible executable, public preflight/request API, usage description, prompt or settings path, reset boundary, and runtime validation. | +| Sandboxed filesystem design and persistent user-selected access | `apple-dev-skills:macos-sandbox-file-access-workflow` | Own containers, open/save panels, bookmarks, standard locations, App Groups, access lifetime, stale resolution, and non-TCC filesystem controls. | +| Capability and entitlement diagnosis | `apple-dev-skills:diagnose-apple-entitlements` | Trace requested capability, tracked project source, account/profile authorization, signed entitlements, nested-code identity, and runtime policy or consent. | +| Account-side bundle IDs, capabilities, certificates, profiles, and CloudKit | `apple-dev-skills:apple-developer-provisioning-workflow` | Retain supported provisioning discovery and mutations after entitlement diagnosis identifies an account-side mismatch. | +| Exported artifacts, Hardened Runtime, Gatekeeper, notarization, and stapling | `apple-dev-skills:macos-distribution-workflow` | Retain distribution-artifact readiness and launch-failure classification. | +| Xcode target, capability, signing, build, install, and run work | Existing Xcode workflows | Apply and validate project changes after a permission or entitlement workflow identifies the owning target and required source change. | +| Exact-build public/private control research | `reverse-engineering-skills:research-macos-security-control` | Own private `kTCCService*` symbols, private entitlements, binaries, frameworks, services, policy implementation, exact-build comparison, and reproducible technical notes. | +| Signed artifact containment inspection | `reverse-engineering-skills:audit-apple-signing-and-containment` | Retain artifact identity, signature, provisioning, entitlement, sandbox, Hardened Runtime, SIP, Data Vault, and declared-versus-observed access evidence. | +| Suspicious prompts, Gatekeeper/XProtect alerts, host activity, hardening, containment, or recovery | Existing `cybersecurity-skills` macOS workflows | Retain threat assessment and defensive decisions; hand ordinary app implementation and deep binary research to their specialist owners. | +| Clean macOS guest selection and preparation | Existing Apple Dev virtualization workflows | Provide an isolated, resettable environment for prompt, identity, signing, quarantine, Gatekeeper, XProtect, and SIP-sensitive validation. | +| Managed-device PPPC policy | Apple deployment documentation plus the owning MDM | Explain payload and identity requirements without pretending a normal app or local CLI can self-grant managed policy. | + +## Control-Layer Model + +Every workflow must name the controlling layer before suggesting a fix: + +1. **Process and code identity**: executable path, bundle identifier, + designated requirement, Team ID, code-signing state, parent/launcher, + helper or XPC boundary, and whether the artifact changed between runs. +2. **Discretionary filesystem access**: ownership, POSIX mode, ACLs, path + resolution, mount state, and ordinary file-operation semantics. +3. **App Sandbox**: app container, App Groups, static sandbox entitlements, + user-selected extensions, security-scoped bookmarks, inherited helpers, and + extension process boundaries. +4. **TCC and privacy consent**: protected service class, responsible code, + prompt or settings behavior, public status/request API, usage description, + user decision, and managed policy. +5. **Capabilities and entitlements**: requested app service, account-side + authorization, provisioning profile, final code-signature entitlements, + restricted/private entitlement status, and runtime enforcement. +6. **Execution and distribution policy**: quarantine/provenance, code signing, + notarization, Gatekeeper, Execution Policy, Hardened Runtime, library + validation, nested code, and stapling. +7. **Malware protection**: XProtect detection and remediation evidence, + security-data versions, Endpoint Security events, and observed behavior. +8. **System integrity and mandatory controls**: SIP, signed system volume, + Data Vaults, platform-binary policy, system extensions, boot security, + recoveryOS decisions, and hardware-dependent protections. + +An administrator account or root access does not collapse these layers. A +successful operation proves only that the recorded artifact performed that +operation in the recorded environment; it does not prove that every layer was +configured as expected. + +## Shared macOS Security Evidence Record + +Each new skill should produce or consume a compact common record while keeping +its own domain-specific result: + +- question and requested decision +- host hardware, architecture, exact macOS version and build, selected SDK and + Xcode, device-management state, and relevant security-update state +- application, executable, helper, service, or artifact identity, including + path, bundle ID, Team ID, designated requirement, signing state, hashes or + UUIDs when useful, parent/launcher, and transformations +- operation attempted, target resource or process, timestamp, user/session, + and whether the observation came from a host, guest, or physical Mac +- controlling layer and permission/service class +- declared project capability, source entitlement, profile authorization, + signed entitlement, usage-description, sandbox, and Hardened Runtime state + when relevant +- public status/preflight API result, request action, user or managed decision, + settings state, restart/relaunch requirement, and reset history +- exact error domain, code, message, log subsystem/category, command, and tool + version rather than a generic `permission denied` summary +- observations, documentation, private implementation evidence, hypotheses, + conclusions, confidence, disproven explanations, and unresolved questions + kept distinct +- mutations performed, approvals received, rollback or reset path, validation + result, and remaining fidelity gaps + +Use this as a consistent handoff shape, not a serialized framework, shared +manager, service, or new repository layer. + +## Skill 1: `macos-privacy-permissions-workflow` + +### Owned job + +Diagnose and implement macOS application-facing privacy and Developer Tools +permission behavior. Start from the attempted operation and responsible +executable, then select the documented framework-specific authorization path. + +### Required coverage + +- Accessibility +- Automation and Apple Events, including the controlling/target application + pair +- Developer Tools through Execution Policy +- Screen and System Audio Recording +- Input Monitoring +- Camera and microphone +- Contacts, calendars, reminders, Photos, media library, location, Bluetooth, + local network, and other framework-owned protected data +- Files & Folders and Full Disk Access boundaries +- App Management and other current macOS-only Privacy & Security classes +- MDM PPPC policy versus ordinary local user consent + +For each class, maintain a version-checked matrix containing: + +- user-visible System Settings name and internal service terminology only when + needed for logs, resets, or research +- public framework and status, preflight, or request API +- required usage-description key +- required entitlement or capability, if any +- whether the app can trigger a prompt, can only create a Settings entry, must + direct the person to Settings, or has no public self-service request path +- whether relaunch, helper restart, logout, or another lifecycle transition is + required after a change +- responsible-code attribution behavior and helper/XPC/launcher implications +- supported `tccutil reset` boundary and a warning that reset is not grant +- MDM support and whether allow, deny, or user approval remains the documented + management result +- minimum host, guest, or physical-device validation fixture + +### Workflow contract + +1. Record the operation and target before naming a permission. +2. Resolve the responsible process and stable signing identity. +3. Consult current Apple docs and the local SDK for the permission class. +4. Inspect usage descriptions, entitlements, sandbox state, helper identity, + and signed result without treating any one as consent. +5. Preflight with the documented public API when available. +6. Request only in direct context of the user action that requires access. +7. Explain why access is needed, what will appear, how denial behaves, and how + to change the decision later. +8. Treat Full Disk Access and other settings-managed classes as explicit user + or MDM decisions; do not invent a grant API. +9. Reproduce the exact operation after the required lifecycle transition. +10. Report the responsible executable, permission class, evidence, result, and + remaining uncertainty. + +### Guards + +- Do not edit, replace, copy back, or directly query the live TCC database as + an application workflow. +- Do not use private `TCC.framework` APIs or `kTCCService*` constants in + shipping guidance; hand private implementation research to Reverse + Engineering. +- Do not describe `tccutil` as a grant or general status tool. +- Do not repeatedly prompt, reset a denial without an explicit test reason, or + automate System Settings clicks to defeat user choice. +- Do not grant a broad terminal, agent host, or IDE permission when a narrower + signed application or helper is the responsible code without explaining the + resulting authority difference. +- Do not run permission-prompt fixtures on Gale's active Mac without explicit + approval immediately before the visible action. + +## Skill 2: `macos-sandbox-file-access-workflow` + +### Owned job + +Choose and implement the narrowest documented filesystem access path for a +macOS app or helper while preserving access lifetime, identity, privacy, and +failure evidence. + +### Required coverage + +- app containers and standard container-relative directories +- App Groups and shared-container identity +- user-selected read-only, read-write, and executable access +- open/save panels, drag and drop, document URLs, and implicit sandbox + extensions +- application-scoped and document-scoped security-scoped bookmarks +- bookmark creation, storage, resolution, stale detection and recreation, + read-only scope, balanced start/stop access, and relaunch behavior +- child resources selected through a directory and documented exceptions +- helper, XPC service, app extension, and inherited-sandbox boundaries +- Downloads and media-folder entitlements where current documentation supports + them +- Full Disk Access and Files & Folders as separate TCC controls +- POSIX permissions, ACLs, symlinks, mounts, file coordination, volumes, + Data Vaults, SIP, and other controls that can still deny access +- explicit handoffs to File Provider/Finder Sync when remote storage or Finder + UI is the actual requirement + +### Workflow contract + +1. Identify the data owner, operation, persistence need, process boundary, and + distribution channel. +2. Use the container or a standard supported directory when that satisfies the + feature. +3. Prefer direct user selection for external files and directories. +4. Create a security-scoped bookmark only when access must survive the current + interaction or process lifetime. +5. Resolve stored bookmark data, detect staleness, recreate stale data, start + access, perform the narrow operation, and balance successful starts with + stops. +6. Record the exact layer producing any remaining denial. +7. Validate relaunch, moved/renamed resources, read-only behavior, helper or + extension access, revoked access, and corrupted bookmark recovery. + +### Guards + +- Do not treat paths as durable authorization tokens or remote identifiers. +- Do not store a security-scoped URL without its bookmark lifecycle. +- Do not retain access indefinitely for convenience. +- Do not claim a bookmark bypasses TCC, Full Disk Access, Data Vaults, SIP, + POSIX permissions, ACLs, or another mandatory control. +- Do not use Finder Sync as a file synchronization or access-grant system. +- Do not log sensitive file paths or bookmark payloads without a specific, + privacy-reviewed diagnostic need. + +## Skill 3: `diagnose-apple-entitlements` + +### Owned job + +Diagnose why an Apple capability or entitlement is missing, rejected, +ineffective, or different between targets and build stages. Determine which +owner must change before handing implementation to Xcode, provisioning, +distribution, or Reverse Engineering. + +### Five-state comparison + +1. **Desired behavior**: operation, target, platform, OS version, distribution + channel, and the current Apple documentation that requires or permits it. +2. **Tracked source**: Xcode capability, `.entitlements` file, `Info.plist` + usage description, build settings, target membership, extension/helper + configuration, and generated-project source of truth. +3. **Account authorization**: App ID capability, restricted-entitlement + approval, provisioning profile, certificate/team, environment, device, and + portal-only or API-supported state. +4. **Signed result**: main executable and every nested helper, extension, + framework, daemon, XPC service, command-line tool, and profile embedded in + the actual built or exported artifact. +5. **Runtime result**: sandbox, Hardened Runtime, library validation, TCC/user + consent, service-mediated authorization, SIP/Data Vault/platform policy, + exact error, and observed access. + +### Required distinctions + +- capability versus entitlement versus usage description +- public, restricted, private/undocumented, development-only, environment, and + exception entitlements +- source entitlement versus profile entitlement versus final signed + entitlement +- application target versus extension/helper/XPC/daemon target +- Debug versus Release, development versus distribution signing, and original + versus re-signed artifact +- declarative capability versus user consent or runtime service authorization +- App Sandbox exception versus Hardened Runtime exception +- local build success versus exported artifact or customer-machine behavior + +### Guards + +- Do not invent entitlement keys, values, availability, approval status, or + profile support. +- Do not hand-edit generated project or profile artifacts to hide a source + mismatch. +- Do not casually re-sign an artifact; treat every transformed copy as a new + artifact and invalidate assumptions about its prior notarization or behavior. +- Do not recommend a private entitlement for an ordinary third-party product. + Hand research questions to Reverse Engineering and account questions to the + provisioning workflow. +- Do not call an entitlement effective until the final executable and runtime + behavior have been checked at the required evidence level. + +## Skill 4: `research-macos-security-control` + +### Owned job + +Research one macOS security or privacy control on an exact build and produce a +reproducible technical note that distinguishes supported public contracts, +private implementation evidence, runtime observations, and hypotheses. + +### Research surfaces + +- TCC frameworks, services, databases, attribution chains, private + `kTCCService*` constants, and changes in service vocabulary +- sandbox profiles, containers, extensions, Seatbelt behavior, and mandatory + access controls +- public and private entitlements, platform-binary context, restricted + entitlements, provisioning, and code requirements +- Execution Policy, quarantine, provenance, Gatekeeper, assessment, XProtect, + notarization, and system-policy services +- Hardened Runtime, library validation, task/debugging policy, SIP, signed + system volume, Data Vaults, system extensions, and boot/recovery policy +- exact-build framework, daemon, XPC, unified-log, Endpoint Security, dyld, + Mach-O, symbol, string, and behavioral differences + +### Workflow contract + +1. State the narrow research question and expected decision. +2. Record host or guest build, hardware, security state, artifact identity, + source provenance, and transformation history. +3. Search Apple docs and public SDK declarations before private implementation. +4. Inspect exact-build binaries, frameworks, services, signatures, + entitlements, strings, symbols, and logs without changing the original. +5. Form a minimal falsifiable hypothesis and choose the least invasive runtime + probe able to test it. +6. Use a clean macOS guest or physical Mac when host state, SIP, recoveryOS, + hardware, or customer fidelity matters. +7. Preserve observations separately from inference; compare exact builds when + claiming change over time. +8. Produce the technical note and hand ordinary application implementation, + distribution repair, threat response, or formal security reporting to the + existing owner. + +### Guards + +- Do not present private symbols, database schemas, log strings, or observed + implementation behavior as a stable supported API. +- Do not mutate live TCC or system-policy databases merely to make research + convenient. +- Do not disable SIP, boot protections, Gatekeeper, XProtect, or other system + protections without a separate exact research goal, recorded state, minimum + necessary change, and explicit approval. +- Do not infer one macOS build's private behavior on another build without + comparison evidence. +- Preserve original artifacts and record every re-sign, patch, extraction, or + environment change. + +## Existing Cybersecurity Workflow Alignment + +Do not add another broad Cybersecurity skill. Update the existing macOS +workflows so their handoffs are unambiguous: + +- `assess-macos-threat` retains suspicious prompts, applications, packages, + profiles, extensions, Gatekeeper or XProtect alerts, unexpected access, and + observed host behavior. It hands ordinary permission implementation to + `macos-privacy-permissions-workflow` and exact private-control questions to + `research-macos-security-control`. +- `inspect-macos-runtime-activity` retains process, file, network, privacy, + unified-log, Endpoint Security, and `eslogger` correlation. It records the + exact permissions needed to collect evidence and does not interpret lack of + telemetry as lack of behavior. +- `harden-macos` retains supported user and managed defensive posture without + teaching developers how to request app permissions. +- `contain-and-recover-macos` retains defensive removal, recovery, and + verification and does not reset or weaken privacy/security controls merely + to make a suspicious artifact run. +- `select-analysis-isolation` and `prepare-isolated-analysis-lab` retain the + SIP-enabled macOS guest as the stable high-fidelity path for control-sensitive + work, with local failure injection explicitly lower fidelity. + +## Resource Topology + +Keep every `SKILL.md` procedural and below 500 lines. Put version-sensitive +matrices and detailed evidence in one-level-deep references loaded only when +the task needs them. + +Planned Apple Dev surface: + +```text +plugins/apple-dev-skills/skills/ +├── macos-privacy-permissions-workflow/ +│ ├── SKILL.md +│ ├── agents/openai.yaml +│ └── references/ +│ ├── permission-class-matrix.md +│ ├── responsible-code-and-attribution.md +│ ├── prompting-settings-reset-and-mdm.md +│ └── validation-fixtures.md +├── macos-sandbox-file-access-workflow/ +│ ├── SKILL.md +│ ├── agents/openai.yaml +│ └── references/ +│ ├── sandbox-and-filesystem-control-map.md +│ ├── security-scoped-bookmark-lifecycle.md +│ ├── helpers-groups-and-process-boundaries.md +│ └── validation-fixtures.md +└── diagnose-apple-entitlements/ + ├── SKILL.md + ├── agents/openai.yaml + └── references/ + ├── five-state-entitlement-comparison.md + ├── restricted-and-private-entitlements.md + ├── artifact-and-nested-code-inspection.md + └── routing-and-validation.md +``` + +Planned Reverse Engineering surface: + +```text +plugins/reverse-engineering-skills/skills/ +└── research-macos-security-control/ + ├── SKILL.md + ├── agents/openai.yaml + └── references/ + ├── source-and-evidence-hierarchy.md + ├── control-research-matrix.md + ├── exact-build-probe-design.md + └── technical-note-contract.md +``` + +Do not add a skill-local README, a duplicated Apple documentation corpus, +machine-local artifacts, copied TCC databases, private binaries, provisioning +profiles, signing identities, or live log captures. + +## Script And Runtime Decision + +The first implementation remains instruction-only. Use documented tools and +explicit commands inside workflows rather than introducing a collector before +the output contract is proven. + +A later read-only diagnostic script is allowed for evaluation only if repeated +fixtures show the same evidence must be gathered across at least three skills. +Before adding it, state the concrete duplication it removes and prove that it: + +- accepts explicit artifact, process, or bundle targets +- defaults to non-mutating inspection +- records `sw_vers`, tool versions, signing identity, entitlements, quarantine, + sandbox, process ancestry, and requested logs without reading secrets or + dumping broad private data +- never grants or resets TCC, changes Gatekeeper, disables protections, edits + databases, re-signs artifacts, or opens System Settings +- emits a documented machine-readable record plus human-friendly diagnostics +- is useful outside Gale's machine and contains no local paths + +An MCP server, privileged helper, daemon, background monitor, endpoint agent, +or GUI permission manager is an architectural pivot and requires a separate +proposal and explicit approval. + +## Implementation Slices + +### Slice 1: Public Privacy Permission Foundation + +- Scaffold `macos-privacy-permissions-workflow` with the skill creator. +- Build the permission-class matrix from current Apple docs and the selected + SDK, starting with Accessibility, Automation, Developer Tools, screen + capture, input, camera/microphone, Files & Folders, and Full Disk Access. +- Add responsible-code attribution, helper/XPC, prompt/settings, denial, + relaunch, reset, and PPPC boundaries. +- Add focused tests for trigger text, public API names, usage-description + ownership, `tccutil` reset-only wording, no-private-API guards, and handoffs. +- Forward-test direct app, Terminal-launched CLI, Xcode-launched app, agent host, + helper, and XPC scenarios without touching the live host's decisions. + +Slice 1 exit criteria: an agent identifies the right permission class and +responsible executable, uses a current supported request path when one exists, +and refuses to invent a grant API when it does not. + +### Slice 2: Filesystem Access And Entitlement Diagnosis + +- Scaffold `macos-sandbox-file-access-workflow` and + `diagnose-apple-entitlements`. +- Add bookmark lifecycle, container, App Group, helper, TCC, POSIX/ACL, Data + Vault, SIP, profile, nested-code, Hardened Runtime, and runtime-consent + references. +- Align `apple-developer-provisioning-workflow`, + `macos-distribution-workflow`, app-extension guidance, File Provider/Finder + Sync, Xcode project guidance, and shared Xcode snippets with the new owners. +- Add focused tests for stale bookmark recovery, balanced access, read-only + scope, relaunch, five-state entitlement comparison, nested helpers, Debug + versus distribution, private-entitlement handoff, and no legacy shim paths. + +Slice 2 exit criteria: an agent can choose persistent file access correctly +and localize an entitlement failure to project source, account/profile, signed +artifact, nested code, or runtime policy without conflating those stages. + +### Slice 3: Exact-Build Security-Control Research + +- Scaffold `research-macos-security-control` under Reverse Engineering Skills. +- Connect it to artifact inspection, signing/containment audit, dynamic + analysis, exact-build comparison, evidence notes, and Apple security report + workflows. +- Add public/private source hierarchy, exact-build probe, technical-note, and + mutation-record references. +- Align Cybersecurity handoffs for suspicious-host and XProtect/Gatekeeper + cases without moving defensive ownership. +- Add tests that reject unsupported API claims, unrecorded cross-build + generalization, casual protection disabling, and transformed-artifact + confusion. + +Slice 3 exit criteria: an agent can research a private or poorly documented +control reproducibly while preserving the line between public contract, +private implementation, runtime observation, and inference. + +### Slice 4: Integration, Compatibility, And Forward Testing + +- Run scenario-level forward tests in fresh contexts using raw fixtures and no + leaked expected answers. +- Update Apple Dev, Reverse Engineering, and Cybersecurity plugin descriptions, + default prompts, keyword inventories, active skill inventories, and root + README text only when the skill surface actually ships. +- Export portable instruction-only skills through the Hermes tap and update + grouping/index entries in the same pass. +- Record Claude Code and Cowork compatibility, keeping Codex-specific MCP or + app metadata out of portable claims. +- Run affected child validation, root metadata validation, Hermes parity, + Claude/Cowork checks, architecture consistency, and the full relevant tests. +- Review whether repeated use earned a shared read-only collector or standalone + plugin. Default to no if the evidence remains workflow-specific. + +Slice 4 exit criteria: every shipped workflow triggers distinctly, hands off +without loops, survives independent scenario testing, and appears consistently +across supported host inventories. + +## Validation Fixtures + +Use locally generated, redistributable, or explicitly approved fixtures. Keep +permission decisions and signing identity stable enough to distinguish a code +change from an identity change. + +1. A minimal signed macOS application with configurable usage descriptions and + one protected operation per test mode. +2. A signed controlling app and target app for Automation/Apple Events. +3. Accessibility and screen-capture preflight/request modes that can run in a + disposable macOS guest. +4. An `EPDeveloperTool` fixture that distinguishes not determined, restricted, + denied, and authorized without claiming that `requestAccess()` shows UI. +5. The same tool reached directly, from Terminal, from Xcode, from an agent + host, and through a helper or XPC service to test responsible-code identity. +6. A sandboxed open-panel fixture that persists a read-only or read-write + security-scoped bookmark, relaunches, balances access, and repairs stale + data. +7. Moved, renamed, removed, revoked, malformed, and inaccessible bookmark + resources with exact error reporting. +8. A generated app/helper/extension bundle matrix with source, profile, and + signed entitlement matches and mismatches. +9. Debug, Release, Developer ID, ad hoc, and intentionally re-signed fixture + copies treated as separate artifacts. +10. Benign quarantined and non-quarantined artifacts for `syspolicy_check`, + `spctl`, signing, notarization, and Gatekeeper classification without + bypassing policy. +11. A clean SIP-enabled macOS guest plus a lower-fidelity local failure-injection + fixture to prove the reporting distinction. +12. Exact-build technical notes comparing one public API, one private symbol or + service string, and one runtime observation across two approved macOS + builds without assuming the difference is causal. + +Automated tests should validate guidance contracts and static fixture +artifacts. Visible prompts, System Settings changes, logout/restart behavior, +and protection-state changes require a separate manual or Computer Use session +with explicit approval and a disposable guest whenever practical. + +## Forward-Test Prompts + +Use fresh worker contexts during implementation. Pass only the completed skill +and raw fixture/request, not this plan's intended diagnosis. + +- "My macOS app says Accessibility is enabled, but its helper still cannot + inspect another app. Diagnose it." +- "Codex can build my tool, but the tool cannot run unsigned development + binaries. Help me handle Developer Tools access correctly." +- "My app controls Finder with Apple Events, but granting Terminal Automation + did not fix the built app." +- "Persist this user-selected directory across app relaunches without asking + for Full Disk Access." +- "The entitlement is present in the `.entitlements` file, but the exported + helper still gets an authorization failure." +- "Determine whether this denial is App Sandbox, TCC, POSIX, Data Vault, or SIP + without weakening my Mac." +- "Explain whether this XProtect event means malware executed and whether the + developer should change the app or the operator should investigate the + host." +- "Research this `kTCCService` symbol on two macOS builds and write a technical + note without treating it as public API." + +Success requires the agent to choose an owner, gather identity and exact-build +evidence, avoid unsupported grants or bypasses, and state what remains +unproven. + +## Documentation And Compatibility + +- Add this plan to root `ROADMAP.md` and the Apple Dev child roadmap in the + planning slice. Do not change README inventory, manifests, marketplace + entries, default prompts, or exported skill inventories until implementation + adds a user-visible skill. +- Keep `SKILL.md` frontmatter descriptions concrete enough to distinguish + permission implementation, filesystem access, entitlement diagnosis, and + private control research. +- Generate `agents/openai.yaml` deterministically from each final skill. +- Keep detailed matrices in directly linked references and recheck their dated + claims against local Apple docs, current SDK headers, Apple Platform + Security, Apple deployment docs, and official web documentation. +- Update the Hermes tap for every portable skill in the same implementation + slice. Do not present Codex plugin metadata as a Hermes plugin. +- Record whether each skill is instruction-portable to Claude Code and Cowork; + preserve host-specific tool and Computer Use requirements as explicit + adapters. +- Do not add an MCP translation unless a later separately approved `.mcp.json` + surface exists. + +## Validation Commands + +Run commands strictly serially and from the owning repository root. + +Planning slice: + +```bash +bash plugins/apple-dev-skills/.github/scripts/validate_repo_docs.sh +uv run scripts/validate_socket_metadata.py +``` + +Implementation slices add, as applicable: + +```bash +cd plugins/apple-dev-skills && uv run pytest +cd plugins/reverse-engineering-skills && uv run scripts/validate_repo_metadata.py +cd plugins/cybersecurity-skills && uv run scripts/validate_repo_metadata.py +uv run scripts/validate_socket_metadata.py +``` + +Also run the repository's current Hermes, Claude/Cowork, architecture, and +release-ready validation gates before a publish or release request. Preserve +full-suite execution for the final integrated slice while using targeted tests +between coherent commits. + +## Branch And Commit Plan + +Use one implementation branch-backed worktree unless a slice must be isolated +for review. Keep Git operations serial and push each coherent checkpoint. + +1. `docs: plan macOS platform security skills` + - this maintainer plan + - root and Apple Dev roadmap entries +2. `apple: add macOS privacy permission workflow` + - Slice 1 skill, references, metadata, tests, and handoffs +3. `apple: add sandbox file and entitlement workflows` + - Slice 2 skills, references, tests, and existing-owner alignment +4. `forensics: add macOS security control research` + - Slice 3 Reverse Engineering skill, references, tests, and Cybersecurity + handoffs +5. `plugin: align macOS security discovery surfaces` + - Slice 4 metadata, inventories, portability exports, docs, integrated tests, + and forward-test remediation + +Do not start version bump, PR, merge, tag, release, marketplace upgrade, or +branch cleanup work unless Gale asks for that lifecycle step. + +## Standalone Plugin Reconsideration Gate + +Reconsider `macos-security-skills` only after the implementation and real use +show all of the following: + +- at least three workflows are routinely needed without Apple Dev, Reverse + Engineering, or Cybersecurity owning the surrounding task +- users experience installation or triggering friction from the split that + explicit handoffs and marketplace catalog installation cannot solve +- a common evidence/runtime surface has a stable, reviewed contract and is not + merely duplicated prose +- moving the skills would reduce ownership ambiguity rather than introduce a + fourth copy of signing, TCC, Gatekeeper, XProtect, or host-response guidance +- Codex, Hermes, Claude, and other supported-host packaging implications are + designed explicitly + +If those conditions are not met, keep the skills in their current specialist +plugins. Socket already gives users one catalog from which to install the +owners together. + +## Planning Slice Boundary + +This planning slice changes only this maintainer plan, root `ROADMAP.md`, and +the Apple Dev child roadmap. It does not add skills, tests, scripts, fixtures, +plugin manifests, marketplace metadata, README inventory text, portability +exports, version bumps, or runtime behavior. + +Implementation is ready to begin when this plan is reviewed and the planning +branch is preserved. Slice 1 is the required starting point because responsible +code identity and public permission APIs establish the evidence vocabulary +that the file-access, entitlement, research, and cybersecurity handoffs consume. diff --git a/plugins/agent-portability-skills/.codex-plugin/plugin.json b/plugins/agent-portability-skills/.codex-plugin/plugin.json index 3dfc5957..493714d7 100644 --- a/plugins/agent-portability-skills/.codex-plugin/plugin.json +++ b/plugins/agent-portability-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "agent-portability-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Maintainer skills for Socket-owned agent skill portability, Codex plugin surfaces, and host adapter guidance.", "author": { "name": "Gale", diff --git a/plugins/agent-portability-skills/pyproject.toml b/plugins/agent-portability-skills/pyproject.toml index 6505d8a3..be4346ad 100644 --- a/plugins/agent-portability-skills/pyproject.toml +++ b/plugins/agent-portability-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "agent-portability-skills-maintenance" -version = "9.20.0" +version = "9.21.0" description = "Maintainer-only Python tooling baseline for Agent Portability Skills." requires-python = ">=3.11" dependencies = [] diff --git a/plugins/agent-portability-skills/uv.lock b/plugins/agent-portability-skills/uv.lock index bb66c02a..4ced2f2b 100644 --- a/plugins/agent-portability-skills/uv.lock +++ b/plugins/agent-portability-skills/uv.lock @@ -8,7 +8,7 @@ resolution-markers = [ [[package]] name = "agent-portability-skills-maintenance" -version = "9.20.0" +version = "9.21.0" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/agentdeck/.codex-plugin/plugin.json b/plugins/agentdeck/.codex-plugin/plugin.json index f73da9ac..5c3ef7bf 100644 --- a/plugins/agentdeck/.codex-plugin/plugin.json +++ b/plugins/agentdeck/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "agentdeck", - "version": "9.20.0", + "version": "9.21.0", "description": "Local Codex runtime utilities for thread, hook, and app-server workflows.", "author": { "name": "Gale", diff --git a/plugins/android-dev-skills/.codex-plugin/plugin.json b/plugins/android-dev-skills/.codex-plugin/plugin.json index c245c69b..d2bb1d09 100644 --- a/plugins/android-dev-skills/.codex-plugin/plugin.json +++ b/plugins/android-dev-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "android-dev-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Android, Kotlin, Java, Gradle, Android Gradle Plugin, testing, lint, UI implementation, and release-readiness workflow skills.", "author": { "name": "Gale", diff --git a/plugins/apple-creator-studio-skills/.codex-plugin/plugin.json b/plugins/apple-creator-studio-skills/.codex-plugin/plugin.json index cb510b7b..07697e11 100644 --- a/plugins/apple-creator-studio-skills/.codex-plugin/plugin.json +++ b/plugins/apple-creator-studio-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "apple-creator-studio-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Human-facing and Computer Use-aware Apple Creator Studio workflows for Final Cut Pro editing, Motion templates, Compressor delivery, Logic Pro production, MainStage concert preparation, and GarageBand projects.", "author": { "name": "Gale", diff --git a/plugins/apple-dev-skills/.codex-plugin/plugin.json b/plugins/apple-dev-skills/.codex-plugin/plugin.json index 7c9e2e2a..4e051b14 100644 --- a/plugins/apple-dev-skills/.codex-plugin/plugin.json +++ b/plugins/apple-dev-skills/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "apple-dev-skills", - "version": "9.20.0", - "description": "Apple development workflows for Codex, including macOS and Linux virtualization, SwiftPM, Xcode, app extensions, imaging, media, Vision/Core ML, spatial sensing, camera, provisioning, SwiftData, SwiftUI, AppKit, Safari, security, OpenAPI, and DocC.", + "version": "9.21.0", + "description": "Apple development workflows for Codex, including macOS privacy permissions, sandbox file access, entitlement diagnosis, virtualization, SwiftPM, Xcode, app extensions, media, provisioning, SwiftUI, AppKit, Safari, security, OpenAPI, and DocC.", "author": { "name": "Gale", "email": "mail@galewilliams.com", @@ -102,6 +102,11 @@ "urlsession", "ios", "macos", + "privacy", + "tcc", + "app-sandbox", + "security-scoped-bookmarks", + "entitlements", "virtualization", "virtual-machine", "linux-vm", @@ -113,7 +118,7 @@ "interface": { "displayName": "Apple Dev Skills", "shortDescription": "Apple Swift, Xcode, virtualization, UI, media, security, and documentation workflows for Codex.", - "longDescription": "Bundle Apple-platform development skills for macOS-hosted boundary selection, custom Virtualization framework hosts, persistent Linux development guests, clean macOS development guests, app extensions, Photos, video, spatial sensing, camera, imaging, Vision and Core ML, audio and media, XcodeGen migration, coding intelligence, localization, Swift, SwiftUI, Core Animation, Apple typography, SF Symbols, AppKit, Safari, security, provisioning, Swift OpenAPI, SwiftPM, DocC, testing, formatting, and repository guidance. Most workflows work standalone; bootstrap and guidance-sync workflows require the companion Productivity Skills plugin, or the Socket marketplace that installs both.", + "longDescription": "Bundle Apple-platform development skills for macOS privacy permissions, sandboxed and persistent file access, entitlement diagnosis, macOS-hosted boundary selection, custom Virtualization framework hosts, persistent Linux development guests, clean macOS development guests, app extensions, Photos, video, spatial sensing, camera, imaging, Vision and Core ML, audio and media, XcodeGen migration, coding intelligence, localization, Swift, SwiftUI, Core Animation, Apple typography, SF Symbols, AppKit, Safari, security, provisioning, Swift OpenAPI, SwiftPM, DocC, testing, formatting, and repository guidance. Most workflows work standalone; bootstrap and guidance-sync workflows require the companion Productivity Skills plugin, or the Socket marketplace that installs both.", "developerName": "Gale", "category": "Developer Tools", "capabilities": [ @@ -122,6 +127,9 @@ ], "websiteURL": "https://github.com/gaelic-ghost/apple-dev-skills", "defaultPrompt": [ + "Diagnose a macOS privacy permission failure from the protected operation and responsible executable, using the documented public status or request path without treating reset, entitlements, or administrator access as a grant.", + "Persist access to a user-selected macOS file or directory across relaunches with the narrowest sandbox entitlement and a complete balanced security-scoped bookmark lifecycle.", + "Trace an Apple entitlement from desired behavior through tracked project source, developer-account and profile authorization, final signed main and nested code, and runtime policy or consent.", "Choose whether this macOS-hosted task belongs on the host, in an OCI container, an Apple container machine, a full Linux or macOS VM, or a physical Mac.", "Design or diagnose a custom macOS or Linux VM host with Apple's Virtualization framework, explicit devices, lifecycle, validation, and save or restore boundaries.", "Prepare and validate a persistent Linux development guest with explicit distro, services, resources, host integrations, nested-virtualization gates, and reset strategy.", diff --git a/plugins/apple-dev-skills/.github/scripts/validate_repo_docs.sh b/plugins/apple-dev-skills/.github/scripts/validate_repo_docs.sh index 3a2558aa..30ecfab2 100644 --- a/plugins/apple-dev-skills/.github/scripts/validate_repo_docs.sh +++ b/plugins/apple-dev-skills/.github/scripts/validate_repo_docs.sh @@ -165,8 +165,11 @@ active_skill_mds=( "./skills/virtualization-framework-workflow/SKILL.md" "./skills/linux-development-vm-workflow/SKILL.md" "./skills/macos-development-vm-workflow/SKILL.md" + "./skills/macos-privacy-permissions-workflow/SKILL.md" + "./skills/macos-sandbox-file-access-workflow/SKILL.md" + "./skills/diagnose-apple-entitlements/SKILL.md" ) -[[ ${#active_skill_mds[@]} -eq 59 ]] || fail "Expected exactly 59 active skills, found ${#active_skill_mds[@]}." +[[ ${#active_skill_mds[@]} -eq 62 ]] || fail "Expected exactly 62 active skills, found ${#active_skill_mds[@]}." shared_xcode_snippet="./shared/agents-snippets/apple-xcode-project-core.md" shared_package_snippet="./shared/agents-snippets/apple-swift-package-core.md" diff --git a/plugins/apple-dev-skills/README.md b/plugins/apple-dev-skills/README.md index a46316ee..f59fb4ce 100644 --- a/plugins/apple-dev-skills/README.md +++ b/plugins/apple-dev-skills/README.md @@ -146,6 +146,9 @@ uv run pytest ## Active Skills +- `macos-privacy-permissions-workflow` +- `macos-sandbox-file-access-workflow` +- `diagnose-apple-entitlements` - `choose-macos-virtualization-shape` - `virtualization-framework-workflow` - `linux-development-vm-workflow` diff --git a/plugins/apple-dev-skills/ROADMAP.md b/plugins/apple-dev-skills/ROADMAP.md index da1176e4..1eacb2d3 100644 --- a/plugins/apple-dev-skills/ROADMAP.md +++ b/plugins/apple-dev-skills/ROADMAP.md @@ -45,6 +45,7 @@ Swift naming and persistence ownership are now standardized: each project explic - [Milestone 66: App Extension, MailKit, and File Provider Workflows](#milestone-66-app-extension-mailkit-and-file-provider-workflows) - [Milestone 67: macOS and Linux Virtualization Workflows](#milestone-67-macos-and-linux-virtualization-workflows) - [Milestone 68: Safari MCP Browser Validation Workflow](#milestone-68-safari-mcp-browser-validation-workflow) +- [Milestone 69: macOS Privacy, File Access, and Entitlement Workflows](#milestone-69-macos-privacy-file-access-and-entitlement-workflows) - [Backlog Candidates](#backlog-candidates) - [History](#history) @@ -107,6 +108,9 @@ Swift naming and persistence ownership are now standardized: each project explic - Milestone 64: Xcode String Catalog Localization Workflow - Completed - Milestone 65: Feedback Assistant Workflow - Completed - Milestone 66: App Extension, MailKit, and File Provider Workflows - Completed +- Milestone 67: macOS and Linux Virtualization Workflows - Completed +- Milestone 68: Safari MCP Browser Validation Workflow - Completed +- Milestone 69: macOS Privacy, File Access, and Entitlement Workflows - Completed ## Milestone 21: Swift Cleanup Automation Exploration @@ -1321,6 +1325,42 @@ Completed - [x] The skill documents data capture, authentication, and irreversible-action limits before live inspection. - [x] Apple Dev Skills and Socket validators cover the authored and Hermes-exported surfaces. +## Milestone 69: macOS Privacy, File Access, and Entitlement Workflows + +### Status + +Completed + +### Scope + +- [x] Use the cross-plugin [`macOS Platform Security Skills Plan`](../../docs/maintainers/macos-platform-security-skills-plan.md) as the implementation source of truth. +- [x] Add `macos-privacy-permissions-workflow` for TCC-related application behavior, responsible-code attribution, public authorization APIs, usage descriptions, prompt/settings lifecycle, supported reset boundaries, and managed PPPC handoffs. +- [x] Add `macos-sandbox-file-access-workflow` for containers, user-selected resources, security-scoped bookmarks, App Groups, helpers, standard locations, and layered filesystem denial diagnosis. +- [x] Add `diagnose-apple-entitlements` for the five-state comparison across desired behavior, tracked project source, account/profile authorization, signed executables, and runtime authorization. +- [x] Preserve provisioning, Xcode execution, distribution, app-extension, File Provider/Finder Sync, virtualization, Reverse Engineering, and Cybersecurity owners through explicit handoffs. +- [x] Keep the initial skills portable and instruction-only, with no permission manager, TCC database access, privileged runtime, or live-host prompt automation. + +### Tickets + +- [x] Scaffold each skill with generated `agents/openai.yaml` metadata only when its implementation slice begins; do not leave placeholder skill directories. +- [x] Build the privacy permission-class matrix from current Apple documentation and local SDK declarations, including Developer Tools through Execution Policy. +- [x] Document responsible applications, command-line launchers, helpers, XPC services, stable code identity, and changed-signature failure cases. +- [x] Document the balanced bookmark lifecycle, stale recreation, read-only scope, relaunch, revocation, helper, and layered-denial contracts. +- [x] Document public, restricted, private, development, environment, sandbox, and Hardened Runtime entitlement categories without inventing availability or approval. +- [x] Add targeted tests and disposable macOS guest fixtures for the complete scenario set in the maintainer plan. +- [x] Align Apple Dev skill metadata, public README inventory, plugin prompts and keywords, shared Xcode guidance, Hermes exports, and Claude/Cowork compatibility only as the new skill surface ships. +- [x] Run targeted tests between slices and the full Apple Dev plus root Socket validation before the integrated implementation is considered complete. + +### Exit Criteria + +- [x] An agent chooses a documented permission API or settings path from the operation and responsible executable rather than treating every Privacy & Security row as the same TCC request. +- [x] An agent can preserve user-selected file access across relaunches without retaining access indefinitely or recommending Full Disk Access by default. +- [x] An agent can localize an entitlement failure to tracked project source, account/profile authorization, final signed nested code, or runtime policy and consent. +- [x] Visible permission prompts and System Settings mutations remain explicit, separately approved validation rather than unattended test behavior on the active Mac. +- [x] Apple Dev metadata, tests, docs, portable exports, and root Socket validation agree on the three new workflow owners. + +Completed Milestone 69 by shipping privacy-permission, sandbox file-access, and five-state entitlement workflows with current public API and local SDK evidence, explicit responsible-code and nested-target diagnosis, complete bookmark lifetime guidance, disposable-fixture contracts, repository metadata, portable exports, and cross-plugin handoffs. The implementation remains instruction-only and requires separate approval for visible permission or System Settings actions. + ## History - Added `safari-extension-control-workflow` as the explicit owner for Safari Web Extension, Safari Web Inspector Extension, Safari App Extension, SafariServices, messaging, content blocker, authentication, and external automation decision guidance. diff --git a/plugins/apple-dev-skills/docs/maintainers/customization-consolidation-review.md b/plugins/apple-dev-skills/docs/maintainers/customization-consolidation-review.md index 9c22b31e..a74f299d 100644 --- a/plugins/apple-dev-skills/docs/maintainers/customization-consolidation-review.md +++ b/plugins/apple-dev-skills/docs/maintainers/customization-consolidation-review.md @@ -8,8 +8,8 @@ Record the Milestone 20 audit of the current customization system, decide whethe ## Current State Summary -- The active skill surface ships `60` separate `references/customization.template.yaml` files. -- The active skill surface ships `60` separate `scripts/customization_config.py` entrypoints. +- The active skill surface ships `63` separate `references/customization.template.yaml` files. +- The active skill surface ships `63` separate `scripts/customization_config.py` entrypoints. - Those `customization_config.py` files are functionally identical and exist only because installed skills are expected to keep runtime resources inside the skill directory. - The current templates expose `21` knobs total: - `20` are documented as `runtime-enforced` @@ -30,7 +30,7 @@ Milestone 20 audited a larger surface before the implementation pass landed. - Milestone 27 applied the approved reduction so the live surface now reflects the smaller counts in the current-state summary above. - Milestone 38 later added the narrower `author-swift-docc-docs` skill with one runtime-enforced tutorial-handling knob, which is included in the current-state counts above. - The current-state counts also include `structure-swift-sources`, which now ships runtime-enforced header-policy and split-threshold knobs for the structural-cleanup workflow. -- The current-state counts now also include the no-runtime-knob `choose-macos-virtualization-shape`, `virtualization-framework-workflow`, `linux-development-vm-workflow`, `macos-development-vm-workflow`, `apple-ui-accessibility-workflow`, `safari-extension-control-workflow`, `safari-mcp-workflow`, `app-extension-architecture-workflow`, `mailkit-workflow`, `file-provider-and-finder-sync-workflow`, `devicecheck-app-attest-workflow`, `apple-developer-provisioning-workflow`, `swiftui-app-architecture-workflow`, `swiftui-component-audit-workflow`, `swiftui-animation-workflow`, `sf-symbols-workflow`, `core-animation-layer-workflow`, `apple-typography-workflow`, `appkit-app-architecture-workflow`, `xcode-coding-intelligence-workflow`, `xcode-localization-workflow`, `migrate-xcode-project-to-xcodegen`, `avfaudio-session-workflow`, `avaudio-engine-workflow`, `avfoundation-media-pipeline-workflow`, `coremedia-timing-samplebuffer-workflow`, and `coreaudio-modernization-repair-workflow` surfaces, all of which keep the customization-file contract without introducing runtime knobs. +- The current-state counts now also include the no-runtime-knob `macos-privacy-permissions-workflow`, `macos-sandbox-file-access-workflow`, `diagnose-apple-entitlements`, `choose-macos-virtualization-shape`, `virtualization-framework-workflow`, `linux-development-vm-workflow`, `macos-development-vm-workflow`, `apple-ui-accessibility-workflow`, `safari-extension-control-workflow`, `safari-mcp-workflow`, `app-extension-architecture-workflow`, `mailkit-workflow`, `file-provider-and-finder-sync-workflow`, `devicecheck-app-attest-workflow`, `apple-developer-provisioning-workflow`, `swiftui-app-architecture-workflow`, `swiftui-component-audit-workflow`, `swiftui-animation-workflow`, `sf-symbols-workflow`, `core-animation-layer-workflow`, `apple-typography-workflow`, `appkit-app-architecture-workflow`, `xcode-coding-intelligence-workflow`, `xcode-localization-workflow`, `migrate-xcode-project-to-xcodegen`, `avfaudio-session-workflow`, `avaudio-engine-workflow`, `avfoundation-media-pipeline-workflow`, `coremedia-timing-samplebuffer-workflow`, and `coreaudio-modernization-repair-workflow` surfaces, all of which keep the customization-file contract without introducing runtime knobs. ## Decision diff --git a/plugins/apple-dev-skills/pyproject.toml b/plugins/apple-dev-skills/pyproject.toml index b1c74d7e..c014834e 100644 --- a/plugins/apple-dev-skills/pyproject.toml +++ b/plugins/apple-dev-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "apple-dev-skills-maintainer" -version = "9.20.0" +version = "9.21.0" description = "Maintainer tooling for the apple-dev-skills repository" requires-python = ">=3.10" dependencies = [] diff --git a/plugins/apple-dev-skills/skills/app-extension-architecture-workflow/SKILL.md b/plugins/apple-dev-skills/skills/app-extension-architecture-workflow/SKILL.md index 845759fb..549d8fcc 100644 --- a/plugins/apple-dev-skills/skills/app-extension-architecture-workflow/SKILL.md +++ b/plugins/apple-dev-skills/skills/app-extension-architecture-workflow/SKILL.md @@ -96,6 +96,8 @@ It owns extension-point routing, target and process boundaries, activation, enti ## Fallbacks and Handoffs +- Recommend `macos-sandbox-file-access-workflow` for user-selected files, security-scoped bookmarks, shared-container access lifetime, and file authorization across an extension process boundary. +- Recommend `diagnose-apple-entitlements` when an extension/helper capability differs between tracked source, profile authorization, final nested signature, and runtime behavior. - Recommend `mailkit-workflow` for the macOS Mail extension point and its handler contracts. - Recommend `file-provider-and-finder-sync-workflow` for remote-storage sync or Finder-only integrations. - Recommend `safari-extension-control-workflow` for Safari-specific extension choices. diff --git a/plugins/apple-dev-skills/skills/apple-developer-provisioning-workflow/SKILL.md b/plugins/apple-dev-skills/skills/apple-developer-provisioning-workflow/SKILL.md index 23b8d849..771fcc1a 100644 --- a/plugins/apple-dev-skills/skills/apple-developer-provisioning-workflow/SKILL.md +++ b/plugins/apple-dev-skills/skills/apple-developer-provisioning-workflow/SKILL.md @@ -95,6 +95,7 @@ The workflow never commits a `.p8` key, CloudKit token, JWT, profile payload, or ## Fallbacks and Handoffs +- Recommend `diagnose-apple-entitlements` when the desired capability, tracked source, account/profile authorization, final signed entitlement, or runtime result disagree; return here only for the account-side correction it identifies. - Recommend `xcode-build-run-workflow` for entitlement, signing, target, build, profile-install, simulator, or device validation work. - Recommend `xcode-coding-intelligence-workflow` for Xcode-hosted inspection or external access through `xcrun mcpbridge`; it owns the running-Xcode and permissions boundary. - Recommend `explore-apple-swift-docs` for current App Store Connect, Xcode, CloudKit, or entitlement documentation lookup. diff --git a/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/SKILL.md b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/SKILL.md new file mode 100644 index 00000000..ba3f92cc --- /dev/null +++ b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/SKILL.md @@ -0,0 +1,73 @@ +--- +name: diagnose-apple-entitlements +description: Trace Apple entitlements across project source, account/profile authorization, final signed main or nested code, and runtime policy or consent. Use for missing or rejected entitlements, export-only failures, helpers, and re-signing. +--- + +# Diagnose Apple Entitlements + +## Purpose + +Trace one desired behavior through tracked project source, developer-account/profile authorization, the final signed artifact and all nested code, and the observed runtime result. Identify the owner that must change without treating an entitlement as user consent or successful access. + +## When To Use + +- Use for capability/entitlement/profile mismatches, export-only failures, nested-code differences, restricted entitlement questions, and re-signed artifacts. +- Use before editing project settings when the actual owner could be the developer account, profile, signer, export transform, runtime policy, or user decision. +- Do not use to invent or recommend private entitlements for ordinary third-party products. + +## Single-Path Workflow + +1. Define the desired operation, target, platform/OS, distribution channel, artifact, and exact runtime error. Apply the Apple docs gate through `explore-apple-swift-docs` and establish whether current Apple documentation requires or permits the capability. +2. Create the five-state record in `references/five-state-entitlement-comparison.md`: desired behavior, tracked source, account/profile authorization, signed result, and runtime result. +3. Inspect tracked source: Xcode capability, `.entitlements`, Info.plist usage description, build settings, target membership, helper/extension/XPC configuration, generated-project source, configuration, and archive/export settings. +4. Inspect account authorization: Team/App ID, capability enablement, restricted-entitlement approval, certificate, provisioning profile entitlements, environment/device scope, and whether the change is portal-only or API-supported. +5. Treat the actual built/exported artifact as source of truth for signed state. Follow `references/artifact-and-nested-code-inspection.md` for the main executable, helpers, extensions, XPC services, frameworks, daemons/tools, and embedded profiles. +6. Compare exact keys and values. Preserve public, restricted, private/undocumented, development-only, environment, and exception classifications only when supported by current evidence. Read `references/restricted-and-private-entitlements.md`. +7. Evaluate runtime controls separately: App Sandbox, Hardened Runtime, library validation, TCC/user consent, service authorization, Gatekeeper/notarization, Data Vault/SIP/platform policy, and responsible process identity. +8. If the artifact was re-signed, patched, exported differently, or otherwise transformed, record a new artifact identity and invalidate assumptions about the original signature/notarization behavior. +9. Classify the mismatch and select exactly one next owner using `references/routing-and-validation.md`. Make the source/account/build change through that owner's workflow, rebuild/export, and repeat the signed and runtime comparisons. +10. Report every state, exact mismatch, owner, evidence/confidence, validation result, and what remains unproven. + +## Inputs + +- desired behavior, target/platform/OS, distribution channel, artifact, and exact error +- project/capability source, build settings, entitlements, Info.plist, and target graph +- Team/App ID/profile/certificate/approval context +- signed main and nested artifacts, embedded profiles, transformations, and runtime environment + +## Outputs + +- five-state entitlement comparison with exact key/value differences +- entitlement classification and responsible owner +- minimum correction/rebuild/export path +- final signed-artifact and runtime validation result with remaining uncertainty + +## Guards and Stop Conditions + +- Do not invent entitlement keys, values, availability, restricted approval, or profile support. +- Do not hand-edit generated project/profile artifacts or casually re-sign a bundle to hide a source mismatch. +- Do not call an entitlement effective until the final responsible executable and required runtime operation are checked. +- Do not confuse a usage description, capability, entitlement, sandbox exception, profile allowance, or user consent. +- Stop when the actual artifact or responsible nested executable is unavailable; report source-only conclusions as unverified. + +## Fallbacks and Handoffs + +- Use `apple-developer-provisioning-workflow` for App ID, capability, certificate, profile, or account-side changes. +- Use Xcode project/build workflows for tracked capability, target, signing, archive, and export changes. +- Use `macos-distribution-workflow` for Hardened Runtime, nested signing, Gatekeeper, notarization, and stapling. +- Use `macos-privacy-permissions-workflow` for user or managed privacy authorization. +- Use `audit-apple-signing-and-containment` for forensic artifact audit and `research-macos-security-control` for private entitlement or exact-build enforcement research. + +## Customization + +Use `references/customization-flow.md`. The workflow has no runtime knobs; comparison states and evidence levels may not be skipped. + +## References + +- `references/five-state-entitlement-comparison.md` +- `references/restricted-and-private-entitlements.md` +- `references/artifact-and-nested-code-inspection.md` +- `references/routing-and-validation.md` +- Recommend `references/snippets/apple-xcode-project-core.md` when the correction belongs to an Xcode target or build configuration. +- [Entitlements](https://developer.apple.com/documentation/bundleresources/entitlements) +- [Diagnosing issues with entitlements](https://developer.apple.com/documentation/bundleresources/diagnosing-issues-with-entitlements) diff --git a/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/agents/openai.yaml b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/agents/openai.yaml new file mode 100644 index 00000000..9f6f9953 --- /dev/null +++ b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Diagnose Apple Entitlements" + short_description: "Trace entitlement state from source to runtime" + default_prompt: "Use $diagnose-apple-entitlements to trace this capability failure from source through runtime." diff --git a/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/artifact-and-nested-code-inspection.md b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/artifact-and-nested-code-inspection.md new file mode 100644 index 00000000..b66cdf55 --- /dev/null +++ b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/artifact-and-nested-code-inspection.md @@ -0,0 +1,22 @@ +# Artifact And Nested-Code Inspection + +## Preserve identity + +Hash or otherwise identify the exact app/package, record its source/export configuration and transformations, and inspect without re-signing. Treat Debug, Release, archive, export, copied, patched, and re-signed variants as different artifacts. + +## Inspect every responsible executable + +Enumerate the main executable, app extensions, XPC services, login/background helpers, privileged helpers, command-line tools/daemons, frameworks with executable code, and embedded provisioning profiles. Record bundle ID, Team ID, designated requirement, signer/flags, and entitlements for each relevant target. + +```bash +codesign --display --verbose=4 /path/to/App.app +codesign --display --entitlements :- /path/to/App.app +codesign --verify --deep --strict --verbose=2 /path/to/App.app +security cms -D -i /path/to/embedded.provisionprofile +``` + +Locate nested code explicitly and run the relevant inspection against each executable. `codesign --deep` verification is not a substitute for comparing nested entitlements and responsible-code identity. + +## Compare + +Compare source entitlements, profile entitlements, final signed entitlements, identifier/team/environment values, sandbox/Hardened Runtime state, and runtime process identity. Do not expose certificate/profile secrets in reports. Rebuild/export from corrected source; do not hand-edit an artifact and present the result as a project fix. diff --git a/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/customization-flow.md b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/customization-flow.md new file mode 100644 index 00000000..11717804 --- /dev/null +++ b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/customization-flow.md @@ -0,0 +1,5 @@ +# Diagnose Apple Entitlements Customization Contract + +The first version defines no runtime-enforced knobs. `scripts/customization_config.py` preserves the shared Apple Dev Skills customization contract; the five-state comparison and final-artifact validation remain mandatory. + +Inspect settings with `scripts/customization_config.py effective`, persist a documented change with `apply --input `, and verify the effective result afterward. diff --git a/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/customization.template.yaml b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/customization.template.yaml new file mode 100644 index 00000000..cddd82d1 --- /dev/null +++ b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/customization.template.yaml @@ -0,0 +1,3 @@ +schemaVersion: 1 +isCustomized: false +settings: {} diff --git a/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/five-state-entitlement-comparison.md b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/five-state-entitlement-comparison.md new file mode 100644 index 00000000..d573833a --- /dev/null +++ b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/five-state-entitlement-comparison.md @@ -0,0 +1,13 @@ +# Five-State Entitlement Comparison + +| State | Capture | Proves | Does not prove | +| --- | --- | --- | --- | +| 1. Desired behavior | Operation/target, platform and OS, distribution, current Apple requirement, exact error | The capability being investigated | Project or account configuration | +| 2. Tracked source | Xcode capability, `.entitlements`, Info.plist, build settings, target membership, generated-project source, helper/extension config | What the repository intends for a configuration | Profile authorization or final signature | +| 3. Account authorization | Team/App ID capability, approval, certificate, profile entitlements, environment/device scope | What Apple/account/profile authorizes for that identity | What the build actually signed or runtime allows | +| 4. Signed result | Main and nested executable entitlements, code requirements, signer/Team ID, embedded profile, Hardened Runtime/signing flags | What the exact artifact declares | User consent, service authorization, or successful access | +| 5. Runtime result | Responsible process, sandbox/TCC/service/system policy, exact error/log, operation result | What this artifact did in this environment | Portable behavior on another build/artifact | + +Compare exact values as well as key presence. Record Debug/Release/archive/export, development/distribution/ad hoc signing, original/re-signed state, and every nested target independently. Classify a mismatch at the first state where expected and observed evidence diverge. + +Keep usage descriptions separate: they explain a privacy request but are not entitlements. Keep Xcode capabilities separate: they may coordinate project and account configuration but are not themselves the final signed value. diff --git a/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/restricted-and-private-entitlements.md b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/restricted-and-private-entitlements.md new file mode 100644 index 00000000..2f4d55bb --- /dev/null +++ b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/restricted-and-private-entitlements.md @@ -0,0 +1,20 @@ +# Restricted And Private Entitlements + +## Classification + +- **Public**: documented for third-party use with published value/platform constraints. +- **Restricted**: documented but requires an Apple approval, request, agreement, or account authorization beyond adding a key. +- **Private or undocumented**: observed in Apple/system artifacts or private interfaces without a supported third-party contract. +- **Development-only**: enables debugger/development behavior and is inappropriate or absent in distribution. +- **Environment-specific**: value binds development/production service state, team, container, or another environment. +- **Exception**: narrowly relaxes App Sandbox or Hardened Runtime behavior; never a general bypass. + +## Decision rules + +Verify the exact key, value type, platform/OS availability, required capability/approval, and provisioning support through current Apple documentation and the selected SDK. Do not infer availability from a symbol/string in another binary or from build success. + +For restricted entitlements, route the account request to `apple-developer-provisioning-workflow` and preserve the response/profile evidence. Adding an unapproved key does not create authorization. + +For private or undocumented entitlements, do not recommend them for an ordinary third-party product. Route legitimate exact-build research to `research-macos-security-control`, and distinguish Apple/platform-binary context from third-party feasibility. + +App Sandbox exceptions and Hardened Runtime exceptions govern different systems. Name the specific restriction being relaxed, use the narrowest documented exception, inspect the final signature, and validate the runtime operation. diff --git a/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/routing-and-validation.md b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/routing-and-validation.md new file mode 100644 index 00000000..5c4fd307 --- /dev/null +++ b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/routing-and-validation.md @@ -0,0 +1,14 @@ +# Routing And Validation + +| First mismatch | Owner | Required validation | +| --- | --- | --- | +| Desired behavior is unsupported or documentation differs | Product/design plus `explore-apple-swift-docs` | Current documented alternative or explicit unsupported state | +| Tracked capability, entitlement, Info.plist, target, or build setting | Xcode project/build workflow | Rebuilt intended configuration and inspected artifact | +| App ID, restricted approval, certificate, or profile | `apple-developer-provisioning-workflow` | Regenerated/refreshed profile plus rebuilt artifact | +| Signed main/nested code differs from source/profile | Xcode build/export or `macos-distribution-workflow` | Exact nested signatures and entitlements after clean export | +| Privacy consent or managed policy | `macos-privacy-permissions-workflow` | Public status/decision plus actual operation | +| Sandbox file authorization | `macos-sandbox-file-access-workflow` | Selection/bookmark/process-boundary result | +| Gatekeeper, notarization, Hardened Runtime, library validation | `macos-distribution-workflow` | Exported artifact assessment/runtime result | +| Private enforcement, platform-binary, SIP/Data Vault, unexplained exact-build policy | Reverse Engineering | Exact-build technical note with observation/inference split | + +After correction, repeat all five states. A local build passing is not customer/distribution proof; an entitlement appearing in a signature is not runtime proof. Report the narrow validated environment and any other distribution, device, OS, helper, or account state that remains untested. diff --git a/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/snippets/apple-xcode-project-core.md b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/snippets/apple-xcode-project-core.md new file mode 120000 index 00000000..fe87bda1 --- /dev/null +++ b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/references/snippets/apple-xcode-project-core.md @@ -0,0 +1 @@ +../../../../shared/agents-snippets/apple-xcode-project-core.md \ No newline at end of file diff --git a/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/scripts/customization_config.py b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/scripts/customization_config.py new file mode 100755 index 00000000..158abb46 --- /dev/null +++ b/plugins/apple-dev-skills/skills/diagnose-apple-entitlements/scripts/customization_config.py @@ -0,0 +1,104 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.9" +# dependencies = ["PyYAML>=6.0.2,<7"] +# /// +"""Load and persist entitlement-diagnosis customization state.""" + +from __future__ import annotations + +import argparse +import os +import re +import sys +from pathlib import Path + +import yaml + +SKILL_NAME = "diagnose-apple-entitlements" +ROOT = "~/.config/gaelic-ghost/apple-dev-skills" +KEYS = {"schemaVersion", "isCustomized", "settings"} + + +def fail(message: str) -> None: + print(f"ERROR: {message}", file=sys.stderr) + raise SystemExit(1) + + +def read(path: Path, required: bool = False) -> dict: + if not path.exists(): + if required: + fail(f"Missing YAML file: {path}") + return {} + try: + value = yaml.safe_load(path.read_text(encoding="utf-8")) or {} + except yaml.YAMLError as error: + fail(f"Invalid YAML in {path}: {error}") + if not isinstance(value, dict): + fail(f"Top-level YAML document must be a mapping in {path}") + return value + + +def validate(value: dict, partial: bool = False) -> None: + if set(value) - KEYS: + fail(f"Unknown top-level keys: {', '.join(sorted(set(value) - KEYS))}") + if not partial and set(value) != KEYS: + fail("State must define schemaVersion, isCustomized, and settings") + if "schemaVersion" in value and value["schemaVersion"] != 1: + fail("schemaVersion must be 1") + if "isCustomized" in value and not isinstance(value["isCustomized"], bool): + fail("isCustomized must be boolean") + if "settings" in value: + if not isinstance(value["settings"], dict): + fail("settings must be a mapping") + for key, item in value["settings"].items(): + if not re.fullmatch(r"[A-Za-z0-9_]+", str(key)): + fail(f"Invalid settings key: {key}") + if isinstance(item, (dict, list)): + fail(f"settings values must be scalar: {key}") + + +def destination() -> Path: + root = Path(os.environ.get("APPLE_DEV_SKILLS_CONFIG_HOME", ROOT)).expanduser() + return root / SKILL_NAME / "customization.yaml" + + +def current() -> dict: + template = read(Path(__file__).resolve().parents[1] / "references/customization.template.yaml", True) + saved = read(destination()) + validate(template) + if saved: + validate(saved) + return {"schemaVersion": 1, "isCustomized": saved.get("isCustomized", False), "settings": {**template["settings"], **saved.get("settings", {})}} + + +def main() -> None: + parser = argparse.ArgumentParser(description="Manage entitlement-diagnosis customization") + command = parser.add_subparsers(dest="command", required=True) + command.add_parser("path") + command.add_parser("effective") + apply = command.add_parser("apply") + apply.add_argument("--input", required=True) + command.add_parser("reset") + args = parser.parse_args() + target = destination() + if args.command == "path": + print(target) + elif args.command == "effective": + print(yaml.safe_dump(current(), sort_keys=False), end="") + elif args.command == "reset": + if target.exists(): + target.unlink() + print(target) + else: + incoming = read(Path(args.input), True) + validate(incoming, partial=True) + updated = {"schemaVersion": 1, "isCustomized": True, "settings": {**current()["settings"], **incoming.get("settings", {})}} + validate(updated) + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(yaml.safe_dump(updated, sort_keys=False), encoding="utf-8") + print(target) + + +if __name__ == "__main__": + main() diff --git a/plugins/apple-dev-skills/skills/file-provider-and-finder-sync-workflow/SKILL.md b/plugins/apple-dev-skills/skills/file-provider-and-finder-sync-workflow/SKILL.md index b2284f1d..8cff5020 100644 --- a/plugins/apple-dev-skills/skills/file-provider-and-finder-sync-workflow/SKILL.md +++ b/plugins/apple-dev-skills/skills/file-provider-and-finder-sync-workflow/SKILL.md @@ -84,6 +84,7 @@ This skill owns that decision, File Provider synchronization mechanics, and Find ## Fallbacks and Handoffs +- Recommend `macos-sandbox-file-access-workflow` when the real requirement is local user-selected files, security-scoped bookmarks, App Groups, or persistent sandbox access rather than a File Provider domain or Finder UI. - Recommend `app-extension-architecture-workflow` for extension targets, process isolation, entitlements, App Groups, and shared containers. - Recommend `swift-openapi-client-workflow` for generated Apple client transport integration. - Recommend `xcode-build-run-workflow` for target configuration, capabilities, signing, embedding, install, and run work. diff --git a/plugins/apple-dev-skills/skills/macos-distribution-workflow/SKILL.md b/plugins/apple-dev-skills/skills/macos-distribution-workflow/SKILL.md index 4f31c957..902fadf4 100644 --- a/plugins/apple-dev-skills/skills/macos-distribution-workflow/SKILL.md +++ b/plugins/apple-dev-skills/skills/macos-distribution-workflow/SKILL.md @@ -47,6 +47,7 @@ Treat a signed exported artifact as the source of truth for macOS distribution d ## Fallbacks and Handoffs +- Recommend `diagnose-apple-entitlements` when source, profile, main or nested signed entitlements, and runtime authorization need a five-state comparison before choosing a repair owner. - Recommend `apple-developer-provisioning-workflow` for documented account-side certificates, profiles, and identifier/capability state. - Recommend `xcode-build-run-workflow` for entitlement/project-signing changes, archive/export, and build validation. - Recommend `explore-apple-swift-docs` for current signing, notarization, or distribution policy. diff --git a/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/SKILL.md b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/SKILL.md new file mode 100644 index 00000000..c54cd9ec --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/SKILL.md @@ -0,0 +1,74 @@ +--- +name: macos-privacy-permissions-workflow +description: Diagnose macOS privacy permissions from the operation and responsible executable. Use for Accessibility, Automation, Developer Tools, recording or input, protected data, Full Disk Access, PPPC, prompts, Settings, resets, and helpers. +--- + +# macOS Privacy Permissions Workflow + +## Purpose + +Identify the protected operation, responsible executable, and current public authorization contract before changing code or asking the person to change Privacy & Security settings. Keep project declarations, user consent, managed policy, and runtime success as separate evidence. + +## When To Use + +- Use for macOS privacy authorization failures, permission prompts, Settings entries, `tccutil reset`, PPPC policy, and responsible-code attribution. +- Use for Accessibility, Automation, Developer Tools, screen/system-audio recording, Input Monitoring, camera, microphone, personal data, Files and Folders, Full Disk Access, App Management, and other current macOS privacy classes. +- Do not use private TCC APIs or database details as an application implementation contract. + +## Single-Path Workflow + +1. Record the exact attempted operation, target resource or process, timestamp, user/session, error domain/code/message, and whether the evidence came from the host, a guest, or a physical Mac. +2. Resolve the responsible code: executable path, bundle identifier, Team ID, designated requirement, signing state, parent/launcher, helper or XPC boundary, and whether the artifact changed. Read `references/responsible-code-and-attribution.md`. +3. Apply the Apple docs gate through `explore-apple-swift-docs`. Record the host macOS version/build and selected SDK/Xcode, then verify the current framework API and settings name. Do not promote an internal service string to a public API. +4. Select the class in `references/permission-class-matrix.md`. Inspect the relevant usage description, entitlement/capability, sandbox state, helper identity, and final signed artifact without treating any declaration as consent. +5. Preflight or read status using the class's documented public API when one exists. Preserve `.notDetermined`, restricted or managed, denied, limited, and authorized states instead of collapsing them to Boolean access. +6. Request only from the user action that needs access and only when the public API supports requesting. Explain the operation, system UI, denial behavior, later Settings path, and any relaunch/helper restart/logout requirement. +7. For Settings-managed classes such as Full Disk Access, describe the user or MDM decision and the narrow responsible executable. Never invent a self-grant API or grant a broad terminal, IDE, or agent host without explaining its broader authority. +8. Read `references/prompting-settings-reset-and-mdm.md` before resetting or managing state. Treat `tccutil reset` as test-state removal, never grant or general status inspection. +9. Reproduce the original operation after the required lifecycle transition. Record the status/preflight result, actual operation result, responsible executable, mutations and approvals, reset/rollback path, and remaining uncertainty. +10. Use the minimum fixture in `references/validation-fixtures.md`. Obtain explicit approval immediately before any visible prompt, System Settings change, logout, or live-host permission mutation. + +## Inputs + +- attempted operation, target, exact error, and expected user-visible behavior +- app/tool/helper path, bundle identity, signer, launcher, and build transformation history +- macOS build, SDK/Xcode, management state, sandbox state, usage descriptions, and signed entitlements +- current status/preflight output, Settings state, prior prompts/resets, and reproduction environment + +## Outputs + +- responsible-code identity and controlling privacy class +- public status/request contract and required project declarations +- prompt, Settings, MDM, reset, lifecycle, and denial behavior +- reproduced operation result, exact evidence, confidence, and unresolved fidelity gaps + +## Guards and Stop Conditions + +- Do not edit, replace, copy back, or directly query a live TCC database as an app workflow. +- Do not use private `TCC.framework` APIs or `kTCCService*` constants in shipping guidance. +- Do not automate System Settings clicks to defeat user choice, repeatedly prompt, or reset a denial without an explicit test reason. +- Do not confuse a usage description, entitlement, sandbox exception, profile payload, or Settings entry with user consent. +- Stop before producing visible permission UI or mutating Gale's active Mac until Gale explicitly approves that exact action. +- Stop when the responsible executable or original protected operation cannot be identified; report the missing evidence instead of guessing a permission. + +## Fallbacks and Handoffs + +- Use `macos-sandbox-file-access-workflow` when user-selected file access, bookmarks, containers, or App Groups are the actual requirement. +- Use `diagnose-apple-entitlements` when source, profile, signed entitlement, and runtime state disagree. +- Use `apple-developer-provisioning-workflow` for account-side capability and profile changes; use Xcode workflows for project edits and builds. +- Use `research-macos-security-control` for private TCC symbols, database schemas, daemon behavior, or exact-build implementation research. +- Use Cybersecurity Skills for suspicious prompts, unexplained grants, Gatekeeper/XProtect alerts, or host compromise questions. + +## Customization + +Use `references/customization-flow.md`. The workflow has no runtime knobs; permission behavior must remain tied to the recorded identity, OS build, public API, and user or managed decision. + +## References + +- `references/permission-class-matrix.md` +- `references/responsible-code-and-attribution.md` +- `references/prompting-settings-reset-and-mdm.md` +- `references/validation-fixtures.md` +- Recommend `references/snippets/apple-xcode-project-core.md` when the diagnosis leads to an Xcode project change. +- [Controlling app access to files in macOS](https://support.apple.com/guide/security/secddd1d86a6/web) +- [Privacy Preferences Policy Control payload](https://support.apple.com/guide/deployment/privacy-preferences-policy-control-payload-dep38df53c2a/web) diff --git a/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/agents/openai.yaml b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/agents/openai.yaml new file mode 100644 index 00000000..0ad3a273 --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "macOS Privacy Permissions" + short_description: "Diagnose macOS privacy permission behavior" + default_prompt: "Use $macos-privacy-permissions-workflow to diagnose this macOS permission failure." diff --git a/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/customization-flow.md b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/customization-flow.md new file mode 100644 index 00000000..b0541694 --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/customization-flow.md @@ -0,0 +1,5 @@ +# macOS Privacy Permissions Customization Contract + +The first version defines no runtime-enforced knobs. `scripts/customization_config.py` preserves the shared Apple Dev Skills customization contract; permission conclusions must remain derived from current documentation, stable code identity, exact host state, and the recorded user or managed decision. + +Inspect settings with `scripts/customization_config.py effective`, persist a documented change with `apply --input `, and verify the effective result afterward. diff --git a/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/customization.template.yaml b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/customization.template.yaml new file mode 100644 index 00000000..cddd82d1 --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/customization.template.yaml @@ -0,0 +1,3 @@ +schemaVersion: 1 +isCustomized: false +settings: {} diff --git a/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/permission-class-matrix.md b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/permission-class-matrix.md new file mode 100644 index 00000000..d61061c4 --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/permission-class-matrix.md @@ -0,0 +1,24 @@ +# macOS Privacy Permission Class Matrix + +Verified baseline: macOS 26.5.2 build 25F84 and the selected stable Xcode SDK on 2026-07-19. Recheck the current SDK declarations and Apple documentation before implementation; System Settings names, APIs, and management results change. + +| User-facing class | Public status/preflight/request path | Declaration or capability | Interaction model | Validation focus | +| --- | --- | --- | --- | --- | +| Accessibility | `AXIsProcessTrustedWithOptions`; the prompt option can direct the user to system UI | No usage-description key; App Sandbox generally cannot provide broad AX control | Check trust for the responsible executable; user or PPPC decision | Helper/host identity, relaunch needs, actual AX operation | +| Automation | `AEDeterminePermissionToAutomateTarget` for a controller-target/event tuple | `NSAppleEventsUsageDescription`; sandboxed senders need the documented Apple Events entitlement/target allowances | Prompt is pair- and event-context-sensitive | Controller-target pair identities, not Terminal's grant | +| Developer Tools | `EPDeveloperTool.authorizationStatus` and `requestAccess()` in ExecutionPolicy | Verify current signing/sandbox constraints in the SDK; no usage-description substitute | Preserve not determined, restricted, denied, authorized; do not promise UI from `requestAccess()` | Direct tool versus Terminal, IDE, agent host, helper/XPC execution | +| Screen and system audio recording | Prefer current ScreenCaptureKit authorization behavior; CoreGraphics exposes `CGPreflightScreenCaptureAccess` and `CGRequestScreenCaptureAccess` for screen capture | Verify current usage-description keys and ScreenCaptureKit requirements in the selected SDK | Public request/preflight exists for screen capture; lifecycle behavior is version-sensitive | Screen-only versus audio selection, app identity, restart/relaunch behavior | +| Input Monitoring | Verify current public event-tap/input APIs and SDK guidance | No generic usage-description key should be invented | Usually a Settings/user or PPPC decision; an attempted protected operation may establish the entry | Event source/type, accessibility overlap, responsible executable | +| Camera and microphone | `AVCaptureDevice.authorizationStatus(for:)` and `requestAccess(for:)` | `NSCameraUsageDescription`, `NSMicrophoneUsageDescription` | Framework request from a direct user action | Device/media type, denial path, actual capture | +| Contacts | Contacts authorization APIs, including the current access level model | `NSContactsUsageDescription` and any newer access-level keys required by the SDK | Framework request; preserve limited/denied distinctions | Requested entity/access level and fetch result | +| Calendars and reminders | EventKit authorization APIs for the requested entity/access level | Current EventKit usage-description keys for events/reminders and access level | Framework request | Event versus reminders, write-only versus full access | +| Photos | `PHPhotoLibrary.authorizationStatus(for:)` and `requestAuthorization(for:)`; use PhotosUI selection when library access is unnecessary | `NSPhotoLibraryUsageDescription` and add-only key as applicable | Prefer user selection or limited access | Access level, selected assets, library operation | +| Location | Core Location authorization/status APIs | Current location usage-description keys | Framework request with service/session lifecycle | Precision, session, authorization level, operation result | +| Bluetooth, local network, media library, speech, and other framework-owned data | Use the owning framework's current authorization API | Use only keys declared by the current SDK/documentation | Framework-specific; no universal TCC request API | Service-specific status plus real operation | +| Files and Folders | No universal app self-grant API | Sandbox entitlements/bookmarks may also apply but do not replace TCC | User or PPPC decision around protected locations | Exact path class and process identity | +| Full Disk Access | No public self-grant or supported general status API | No entitlement grants ordinary third-party FDA | Explicit user or supported MDM policy decision | Narrow responsible executable, lifecycle transition, original operation | +| App Management and other current macOS-only classes | Verify current public API and deployment payload support | Do not infer a key or entitlement from an internal TCC service name | Often Settings/user or managed policy | Operation, actor/target identity, exact OS build | + +Use internal service terminology only when it is necessary to interpret a log, supported reset command, or exact-build research note. Route private constants and implementation behavior to `research-macos-security-control`. + +Sources: [Apple Platform Security](https://support.apple.com/guide/security/welcome/web), [Controlling app access to files](https://support.apple.com/guide/security/secddd1d86a6/web), [PPPC payload settings](https://support.apple.com/guide/deployment/privacy-preferences-policy-control-payload-dep38df53c2a/web), and the selected SDK headers. diff --git a/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/prompting-settings-reset-and-mdm.md b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/prompting-settings-reset-and-mdm.md new file mode 100644 index 00000000..e00a287e --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/prompting-settings-reset-and-mdm.md @@ -0,0 +1,24 @@ +# Prompting, Settings, Reset, And MDM + +## Request lifecycle + +1. Preflight or read the framework status without prompting when the API supports it. +2. Request from a direct user action only when the status and public contract allow a request. +3. Explain the concrete operation and target before system UI appears. +4. Preserve denied, restricted/managed, limited, and authorized as distinct states. +5. Provide a non-coercive denial path and the current Privacy & Security location when a later change is possible. +6. Apply the documented relaunch, helper restart, logout, or retry boundary, then reproduce the original operation. + +Never loop requests, hide the responsible app behind a generic host, or automate Settings to defeat consent. + +## Reset boundary + +`tccutil` is a supported reset surface, not a general grant or status tool. Before a reset, record the service/class, bundle identity, reason, current reproduction, expected next prompt, and rollback/test cleanup. Use only the syntax supported by `man tccutil` on the current OS. A reset removes a decision; it does not authorize access. + +Do not manipulate a live TCC database, copy an edited database back, or use SQL output as an app-facing support contract. Use private schemas only in an approved exact-build Reverse Engineering task. + +## MDM and PPPC + +PPPC identifies code using the documented bundle/code requirement fields and supports only the service classes and authorization values Apple documents for the current OS. A payload may allow, deny, or require user approval depending on the class; do not assume MDM can silently allow every permission. Record supervision/enrollment state, payload scope, designated requirement, authorization value, conflict/precedence evidence, and the device's applied-profile state. + +Use [Apple's PPPC payload documentation](https://support.apple.com/guide/deployment/privacy-preferences-policy-control-payload-dep38df53c2a/web) as the source of truth for current services and allowed authorization values. diff --git a/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/responsible-code-and-attribution.md b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/responsible-code-and-attribution.md new file mode 100644 index 00000000..258b3f1c --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/responsible-code-and-attribution.md @@ -0,0 +1,29 @@ +# Responsible Code And Attribution + +## Identity record + +Capture the executable path, bundle ID, Team ID, designated requirement, signing flags, CDHash when useful, parent/launcher, target process/resource, and transformation history. For a helper, extension, XPC service, script interpreter, or command-line tool, record both the initiating app and the process that performs the protected operation. + +Useful non-mutating inspection commands include: + +```bash +codesign --display --verbose=4 /path/to/App.app +codesign --display --entitlements :- /path/to/App.app +codesign --verify --deep --strict --verbose=2 /path/to/App.app +ps -axo pid,ppid,user,comm,args +``` + +Do not rely on `--deep` verification alone to explain nested-code identity; enumerate the actual helper/extension/XPC executables when attribution matters. + +## Attribution traps + +- A grant to Terminal, an IDE, or an agent host authorizes that signed host in the recorded context; it does not prove the built app or helper is authorized. +- Rebuilding, relocating, changing signing identity, re-signing, or launching through a different host can change the identity that TCC evaluates. +- Automation is about the controlling-target pair and requested Apple Event, not one global permission. +- A helper or XPC service can be the responsible code even when the parent app owns the UI. +- Unsigned, ad hoc, or unstable development tools make authorization evidence difficult to reproduce. Preserve the exact artifact instead of generalizing one result. +- A Settings entry is not proof that the original operation now succeeds; reproduce the operation after any required relaunch, helper restart, or logout. + +## Result statement + +Report: `artifact identity -> protected operation and target -> class/status evidence -> user or managed decision -> lifecycle transition -> reproduced result`. State whether attribution is documented, observed, or inferred. diff --git a/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/snippets/apple-xcode-project-core.md b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/snippets/apple-xcode-project-core.md new file mode 120000 index 00000000..fe87bda1 --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/snippets/apple-xcode-project-core.md @@ -0,0 +1 @@ +../../../../shared/agents-snippets/apple-xcode-project-core.md \ No newline at end of file diff --git a/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/validation-fixtures.md b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/validation-fixtures.md new file mode 100644 index 00000000..51e17c82 --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/references/validation-fixtures.md @@ -0,0 +1,19 @@ +# Privacy Permission Validation Fixtures + +## Minimum fixture matrix + +Use disposable, signed fixtures with one protected operation per mode: + +- Accessibility status/request plus one harmless AX read against a named target. +- A signed Apple Events controller and target so the controller-target pair is explicit. +- Screen-capture preflight/request and one bounded capture in a disposable guest. +- `EPDeveloperTool` status/request preserving all declared authorization states. +- The same development tool reached directly, from Terminal, an IDE, an agent host, and a helper/XPC process. +- One framework-owned personal-data class with correct, missing, and malformed usage descriptions. +- A Files and Folders or Full Disk Access denial that validates the Settings-managed boundary without attempting self-grant. + +## Test record + +Record fixture commit/hash, bundle ID, signer/Team ID/designated requirement, macOS build, SDK/Xcode, guest/physical status, management state, prior decision/reset history, invocation path, status/preflight, visible UI, lifecycle transition, exact error, and actual operation result. + +Automated checks may validate source declarations, signed identities, expected state handling, and reporting contracts. A visible prompt, System Settings edit, logout/restart, PPPC install, or live-host permission mutation requires separate explicit approval immediately before execution. Prefer a resettable SIP-enabled macOS guest; label local failure injection as lower fidelity. diff --git a/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/scripts/customization_config.py b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/scripts/customization_config.py new file mode 100755 index 00000000..8474f269 --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-privacy-permissions-workflow/scripts/customization_config.py @@ -0,0 +1,138 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.9" +# dependencies = ["PyYAML>=6.0.2,<7"] +# /// +"""Load and persist macOS privacy workflow customization state.""" + +from __future__ import annotations + +import argparse +import os +import re +import sys +from pathlib import Path + +import yaml + +SKILL_NAME = "macos-privacy-permissions-workflow" +CONFIG_HOME_ENV = "APPLE_DEV_SKILLS_CONFIG_HOME" +DEFAULT_CONFIG_ROOT = "~/.config/gaelic-ghost/apple-dev-skills" +ALLOWED_KEYS = {"schemaVersion", "isCustomized", "settings"} + + +def fail(message: str) -> None: + print(f"ERROR: {message}", file=sys.stderr) + raise SystemExit(1) + + +def load(path: Path, *, required: bool) -> dict: + if not path.exists(): + if required: + fail(f"Missing YAML file: {path}") + return {} + try: + data = yaml.safe_load(path.read_text(encoding="utf-8")) or {} + except yaml.YAMLError as error: + fail(f"Invalid YAML in {path}: {error}") + if not isinstance(data, dict): + fail(f"Top-level YAML document must be a mapping in {path}") + return data + + +def validate(data: dict, *, partial: bool) -> None: + unknown = set(data) - ALLOWED_KEYS + if unknown: + fail(f"Unknown top-level keys: {', '.join(sorted(unknown))}") + if not partial and set(data) != ALLOWED_KEYS: + fail("Customization state must define schemaVersion, isCustomized, and settings") + if "schemaVersion" in data and data["schemaVersion"] != 1: + fail("schemaVersion must be 1") + if "isCustomized" in data and not isinstance(data["isCustomized"], bool): + fail("isCustomized must be boolean") + if "settings" in data: + if not isinstance(data["settings"], dict): + fail("settings must be a mapping") + for key, value in data["settings"].items(): + if not re.fullmatch(r"[A-Za-z0-9_]+", str(key)): + fail(f"Invalid settings key: {key}") + if isinstance(value, (dict, list)): + fail(f"settings values must be scalar: {key}") + + +def template_path() -> Path: + return Path(__file__).resolve().parents[1] / "references" / "customization.template.yaml" + + +def durable_path() -> Path: + root = Path(os.environ.get(CONFIG_HOME_ENV, DEFAULT_CONFIG_ROOT)).expanduser() + return root / SKILL_NAME / "customization.yaml" + + +def effective() -> dict: + base = load(template_path(), required=True) + saved = load(durable_path(), required=False) + validate(base, partial=False) + validate(saved, partial=False) if saved else None + merged = { + "schemaVersion": saved.get("schemaVersion", base["schemaVersion"]), + "isCustomized": saved.get("isCustomized", base["isCustomized"]), + "settings": {**base["settings"], **saved.get("settings", {})}, + } + validate(merged, partial=False) + return merged + + +def render(data: dict) -> str: + return yaml.safe_dump(data, sort_keys=False, default_flow_style=False) + + +def command_path(_: argparse.Namespace) -> None: + print(durable_path()) + + +def command_effective(_: argparse.Namespace) -> None: + print(render(effective()), end="") + + +def command_apply(args: argparse.Namespace) -> None: + incoming = load(Path(args.input), required=True) + validate(incoming, partial=True) + current = effective() + updated = { + "schemaVersion": 1, + "isCustomized": True, + "settings": {**current["settings"], **incoming.get("settings", {})}, + } + validate(updated, partial=False) + target = durable_path() + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(render(updated), encoding="utf-8") + print(target) + + +def command_reset(_: argparse.Namespace) -> None: + target = durable_path() + if target.exists(): + target.unlink() + print(target) + + +def main() -> None: + parser = argparse.ArgumentParser(description="Manage macOS privacy workflow customization") + commands = parser.add_subparsers(dest="command", required=True) + path_parser = commands.add_parser("path") + path_parser.set_defaults(func=command_path) + effective_parser = commands.add_parser("effective") + effective_parser.set_defaults(func=command_effective) + apply_parser = commands.add_parser("apply") + apply_parser.add_argument("--input", required=True) + apply_parser.set_defaults(func=command_apply) + reset_parser = commands.add_parser("reset") + reset_parser.set_defaults(func=command_reset) + args = parser.parse_args() + args.func(args) + + +if __name__ == "__main__": + main() diff --git a/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/SKILL.md b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/SKILL.md new file mode 100644 index 00000000..0e91e6bb --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/SKILL.md @@ -0,0 +1,74 @@ +--- +name: macos-sandbox-file-access-workflow +description: Design and diagnose macOS file access. Use for App Sandbox, App Groups, user selection, security-scoped bookmarks across relaunches, helpers or extensions, stale access, TCC overlap, POSIX or ACL, Data Vault, and SIP denials. +--- + +# macOS Sandbox File Access Workflow + +## Purpose + +Preserve user intent and access lifetime while selecting the smallest supported file-access mechanism. Treat a URL or path as resource identity, not durable authorization, and keep App Sandbox, TCC, POSIX, and mandatory controls distinct. + +## When To Use + +- Use when a sandboxed Mac app must open, save, import, export, drag, share, or persist access to files or directories. +- Use when access succeeds during selection but fails after relaunch, in a helper, or after a move/rename. +- Use to identify whether a remaining denial is sandbox, TCC, filesystem, volume, coordination, Data Vault, or SIP policy. + +## Single-Path Workflow + +1. Record the data owner, exact operation, resource type, read/write/execute need, persistence duration, process boundary, distribution channel, macOS build, and exact error. +2. Read `references/sandbox-and-filesystem-control-map.md` and identify every applicable control layer before choosing a capability. +3. Use the app container or a standard supported container-relative directory when it satisfies the feature. Use an App Group only for a real same-team shared-container requirement. +4. Prefer direct user selection through the appropriate open/save panel, document URL, drag/drop, or Photos/File Provider selection surface for external data. +5. Request only the user-selected read-only, read-write, or executable entitlement that the feature actually needs. Do not replace a narrow selection with Full Disk Access. +6. Create a security-scoped bookmark only when access must survive the current interaction or process lifetime. Follow every step in `references/security-scoped-bookmark-lifecycle.md`. +7. For helpers, XPC services, app extensions, or shared containers, use `references/helpers-groups-and-process-boundaries.md`; verify which process resolves and consumes authorization rather than passing a path and assuming authority follows. +8. Perform the narrow operation and balance every successful `startAccessingSecurityScopedResource()` with `stopAccessingSecurityScopedResource()`. Do not retain access indefinitely for convenience. +9. If access still fails, classify the exact denying layer: path resolution/symlink, ownership/mode/ACL, sandbox, TCC Files and Folders/Full Disk Access, mount/volume state, coordination, Data Vault, SIP, or service policy. +10. Validate relaunch, moved/renamed/removed resources, read-only enforcement, helper/extension behavior, revoked/inaccessible access, stale and malformed bookmark recovery, and privacy-safe logging using `references/validation-fixtures.md`. + +## Inputs + +- resource owner, selection path, operation, persistence need, and distribution channel +- app/helper/extension identities, sandbox entitlements, App Group, and signed artifacts +- bookmark creation/storage/resolution code and exact errors +- macOS build, volume/mount, POSIX/ACL, TCC, Data Vault, and SIP context + +## Outputs + +- selected access mechanism and least-privilege entitlement set +- bookmark ownership, storage, resolution, lifetime, and repair contract +- process-boundary authorization design +- exact denying layer, reproduced result, privacy-safe evidence, and unresolved gaps + +## Guards and Stop Conditions + +- Do not treat a path, URL, alias, file ID, or remote identifier as a durable authorization token. +- Do not store only a security-scoped URL or retain access indefinitely. +- Do not claim a bookmark bypasses TCC, Full Disk Access, Data Vaults, SIP, POSIX permissions, ACLs, mounts, or service policy. +- Do not log bookmark bytes or sensitive full paths without a specific privacy-reviewed diagnostic need. +- Do not use Finder Sync as a synchronization engine or access-grant mechanism. +- Stop when the resource owner, operation, persistence duration, or consuming process is unknown. + +## Fallbacks and Handoffs + +- Use `macos-privacy-permissions-workflow` for Files and Folders, Full Disk Access, or another TCC decision. +- Use `diagnose-apple-entitlements` when source, profile, or final signed sandbox/App Group entitlements disagree. +- Use `file-provider-and-finder-sync-workflow` for remote storage, File Provider domains, or Finder UI decoration. +- Use `app-extension-architecture-workflow` for extension lifecycle/IPC design and Xcode workflows for project edits. +- Use `research-macos-security-control` for private sandbox profiles, extensions, or exact-build Seatbelt behavior. + +## Customization + +Use `references/customization-flow.md`. The workflow has no runtime knobs; access scope must follow the recorded feature, process, resource, and lifetime. + +## References + +- `references/sandbox-and-filesystem-control-map.md` +- `references/security-scoped-bookmark-lifecycle.md` +- `references/helpers-groups-and-process-boundaries.md` +- `references/validation-fixtures.md` +- Recommend `references/snippets/apple-xcode-project-core.md` when implementing target entitlements or helper membership. +- [Protecting user data with App Sandbox](https://developer.apple.com/documentation/security/protecting-user-data-with-app-sandbox) +- [Accessing files from the macOS App Sandbox](https://developer.apple.com/documentation/security/accessing-files-from-the-macos-app-sandbox) diff --git a/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/agents/openai.yaml b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/agents/openai.yaml new file mode 100644 index 00000000..1f09357d --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "macOS Sandbox File Access" + short_description: "Design durable sandboxed file access" + default_prompt: "Use $macos-sandbox-file-access-workflow to design the narrowest durable file-access path." diff --git a/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/customization-flow.md b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/customization-flow.md new file mode 100644 index 00000000..8f5781c8 --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/customization-flow.md @@ -0,0 +1,5 @@ +# macOS Sandbox File Access Customization Contract + +The first version defines no runtime-enforced knobs. `scripts/customization_config.py` preserves the shared Apple Dev Skills customization contract; access scope must be selected from the concrete resource, process, operation, distribution, and persistence need. + +Inspect settings with `scripts/customization_config.py effective`, persist a documented change with `apply --input `, and verify the effective result afterward. diff --git a/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/customization.template.yaml b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/customization.template.yaml new file mode 100644 index 00000000..cddd82d1 --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/customization.template.yaml @@ -0,0 +1,3 @@ +schemaVersion: 1 +isCustomized: false +settings: {} diff --git a/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/helpers-groups-and-process-boundaries.md b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/helpers-groups-and-process-boundaries.md new file mode 100644 index 00000000..f2db778a --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/helpers-groups-and-process-boundaries.md @@ -0,0 +1,21 @@ +# Helpers, Groups, And Process Boundaries + +## App Groups + +Use an App Group only when separately signed targets from the same developer team need a documented shared container or service. Match the group identifier in tracked project capabilities, developer-account/profile authorization when applicable, and final entitlements of every consumer. An App Group does not grant access to arbitrary external paths. + +## Helpers and XPC services + +- Record which executable receives the user-selected URL, creates bookmark data, stores it, resolves it, starts access, and performs I/O. +- Do not pass a path across IPC and assume authorization follows. +- Prefer the parent process perform the file operation and exchange bounded data when that keeps authority narrower. +- If another process must consume the resource, verify the documented sandbox inheritance or bookmark transfer contract for that process type and distribution channel. +- Inspect the final signed entitlements and embedded profile of the helper/XPC service, not only the app target. + +## Extensions + +App extensions run in separate processes with their own entitlements, containers, lifecycle, and host-mediated inputs. Use extension-provided URLs only within their documented lifetime unless a supported bookmark contract says otherwise. Route extension architecture to `app-extension-architecture-workflow`. + +## Directory selection + +A user-selected directory may authorize descendants under the documented sandbox extension/bookmark behavior, subject to read/write scope and other controls. Do not generalize that to siblings, symlink escapes, other volumes, TCC-protected locations, or a remote identity model. diff --git a/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/sandbox-and-filesystem-control-map.md b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/sandbox-and-filesystem-control-map.md new file mode 100644 index 00000000..4e84b42b --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/sandbox-and-filesystem-control-map.md @@ -0,0 +1,19 @@ +# Sandbox And Filesystem Control Map + +Evaluate controls in order and preserve the exact error at each boundary. + +| Layer | Question | Typical evidence | Correct owner | +| --- | --- | --- | --- | +| Resource identity | Does the URL still identify the intended file after move, rename, symlink, alias, volume remount, or replacement? | Standardized/resolved URL, resource identifiers, volume identity | App data model | +| POSIX and ACL | Does the process identity have discretionary access? | `stat`, `ls -le`, ownership/mode/ACL, exact `errno` | File owner/admin/user | +| App container | Does a container-relative location satisfy the feature? | Container path, bundle identity, sandbox container | App architecture | +| App Sandbox | Does the signed process have a static entitlement or current sandbox extension? | Final signed entitlements, process boundary, selection event, sandbox-denial log | Apple Dev workflow | +| Security-scoped bookmark | Was durable authorization created, stored, resolved, checked for staleness, and activated? | Bookmark lifecycle and Foundation errors | Apple Dev workflow | +| TCC | Is the location separately protected by Files and Folders or Full Disk Access? | Responsible code, public/Settings state, operation result | Privacy workflow | +| Mount/volume | Is the volume present, writable, unlocked, and compatible with the requested semantics? | Mount flags, filesystem, availability/eject state | App/OS/storage | +| Coordination/service | Does another process or service own coordinated access? | `NSFileCoordinator`/presenter or service error | Framework owner | +| Data Vault/SIP/mandatory policy | Is a mandatory system policy denying the operation despite root or discretionary permission? | Exact OS build, path class, logs, SIP/system state | Public docs or exact-build research | + +Static sandbox entitlements include the app container, documented standard-folder exceptions, App Groups, and user-selected access classes. A user interaction can issue a temporary sandbox extension; a security-scoped bookmark preserves supported authorization for later resolution. Neither is a universal filesystem capability. + +Downloads/media-folder entitlements are version- and distribution-sensitive. Verify the current [App Sandbox entitlement documentation](https://developer.apple.com/documentation/bundleresources/entitlements/com.apple.security.app-sandbox) and final signature before recommending one. diff --git a/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/security-scoped-bookmark-lifecycle.md b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/security-scoped-bookmark-lifecycle.md new file mode 100644 index 00000000..e4ed082d --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/security-scoped-bookmark-lifecycle.md @@ -0,0 +1,47 @@ +# Security-Scoped Bookmark Lifecycle + +## Creation + +1. Receive a URL from a supported user-selection or document interaction. +2. Choose application-scoped or document-scoped behavior and read-only scope deliberately; verify the current platform API and entitlement requirements. +3. Create bookmark data with the appropriate security-scope options. +4. Store the bookmark bytes as sensitive authorization state. Associate them with a stable app record, not merely a path string. + +## Resolution and use + +1. Load bookmark data and resolve it with matching security-scope options. +2. Capture the stale result. If stale, recreate and persist bookmark data from the resolved URL before treating repair as complete. +3. Call `startAccessingSecurityScopedResource()` immediately around the narrow operation. +4. Balance a successful start with `stopAccessingSecurityScopedResource()` using structured cleanup such as `defer`. Do not stop when start returned false, and do not hold access for the app lifetime by default. +5. Preserve Foundation error domain/code/message and the later file-operation error separately. + +```swift +var stale = false +let url = try URL( + resolvingBookmarkData: data, + options: [.withSecurityScope], + relativeTo: nil, + bookmarkDataIsStale: &stale +) + +if stale { + let repaired = try url.bookmarkData( + options: [.withSecurityScope], + includingResourceValuesForKeys: nil, + relativeTo: nil + ) + try persist(repaired) +} + +let started = url.startAccessingSecurityScopedResource() +defer { + if started { url.stopAccessingSecurityScopedResource() } +} +try performNarrowOperation(at: url) +``` + +Adapt options and storage to the current documented API, sandbox shape, and read-only requirement. Validate selection-session access separately from post-relaunch bookmark access. + +## Failure matrix + +Test valid, stale, corrupt, missing, moved, renamed, removed, inaccessible, revoked, read-only, wrong-scope, wrong-process, and volume-offline cases. A resolved URL does not prove the file operation is authorized; another layer can still deny it. diff --git a/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/snippets/apple-xcode-project-core.md b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/snippets/apple-xcode-project-core.md new file mode 120000 index 00000000..fe87bda1 --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/snippets/apple-xcode-project-core.md @@ -0,0 +1 @@ +../../../../shared/agents-snippets/apple-xcode-project-core.md \ No newline at end of file diff --git a/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/validation-fixtures.md b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/validation-fixtures.md new file mode 100644 index 00000000..f78d3915 --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/references/validation-fixtures.md @@ -0,0 +1,15 @@ +# Sandbox File Access Validation Fixtures + +Build a signed sandboxed fixture with open-panel selection and separate read-only/read-write modes. Persist bookmark data, terminate fully, relaunch, resolve, repair stale data, start access, perform one operation, and balance stop access. + +Cover: + +- file and directory selection; open/save, drag/drop, and document URLs +- selection-session access versus clean relaunch +- moved, renamed, removed, malformed, stale, revoked/inaccessible, and volume-offline resources +- read-only enforcement and attempted write +- main app, helper, XPC service, and extension consumers +- App Group match/mismatch across source, profile, and final signatures +- POSIX mode/ACL, symlink, mount, TCC-protected location, Data Vault, and SIP denials + +Record app and consumer identities, exact macOS build/SDK, sandbox and signed entitlements, selection source, bookmark options, stale/start results, exact Foundation and file errors, privacy-redacted path identity, operation result, and cleanup. Automated fixtures must use generated nonsensitive paths; visible prompts or Settings changes require explicit approval and preferably a disposable guest. diff --git a/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/scripts/customization_config.py b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/scripts/customization_config.py new file mode 100755 index 00000000..7c8b797e --- /dev/null +++ b/plugins/apple-dev-skills/skills/macos-sandbox-file-access-workflow/scripts/customization_config.py @@ -0,0 +1,104 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.9" +# dependencies = ["PyYAML>=6.0.2,<7"] +# /// +"""Load and persist sandbox file-access workflow customization state.""" + +from __future__ import annotations + +import argparse +import os +import re +import sys +from pathlib import Path + +import yaml + +SKILL_NAME = "macos-sandbox-file-access-workflow" +ROOT = "~/.config/gaelic-ghost/apple-dev-skills" +KEYS = {"schemaVersion", "isCustomized", "settings"} + + +def fail(message: str) -> None: + print(f"ERROR: {message}", file=sys.stderr) + raise SystemExit(1) + + +def read(path: Path, required: bool = False) -> dict: + if not path.exists(): + if required: + fail(f"Missing YAML file: {path}") + return {} + try: + value = yaml.safe_load(path.read_text(encoding="utf-8")) or {} + except yaml.YAMLError as error: + fail(f"Invalid YAML in {path}: {error}") + if not isinstance(value, dict): + fail(f"Top-level YAML document must be a mapping in {path}") + return value + + +def validate(value: dict, partial: bool = False) -> None: + if set(value) - KEYS: + fail(f"Unknown top-level keys: {', '.join(sorted(set(value) - KEYS))}") + if not partial and set(value) != KEYS: + fail("State must define schemaVersion, isCustomized, and settings") + if "schemaVersion" in value and value["schemaVersion"] != 1: + fail("schemaVersion must be 1") + if "isCustomized" in value and not isinstance(value["isCustomized"], bool): + fail("isCustomized must be boolean") + if "settings" in value: + if not isinstance(value["settings"], dict): + fail("settings must be a mapping") + for key, item in value["settings"].items(): + if not re.fullmatch(r"[A-Za-z0-9_]+", str(key)): + fail(f"Invalid settings key: {key}") + if isinstance(item, (dict, list)): + fail(f"settings values must be scalar: {key}") + + +def destination() -> Path: + root = Path(os.environ.get("APPLE_DEV_SKILLS_CONFIG_HOME", ROOT)).expanduser() + return root / SKILL_NAME / "customization.yaml" + + +def current() -> dict: + template = read(Path(__file__).resolve().parents[1] / "references/customization.template.yaml", True) + saved = read(destination()) + validate(template) + if saved: + validate(saved) + return {"schemaVersion": 1, "isCustomized": saved.get("isCustomized", False), "settings": {**template["settings"], **saved.get("settings", {})}} + + +def main() -> None: + parser = argparse.ArgumentParser(description="Manage sandbox file-access customization") + command = parser.add_subparsers(dest="command", required=True) + command.add_parser("path") + command.add_parser("effective") + apply = command.add_parser("apply") + apply.add_argument("--input", required=True) + command.add_parser("reset") + args = parser.parse_args() + target = destination() + if args.command == "path": + print(target) + elif args.command == "effective": + print(yaml.safe_dump(current(), sort_keys=False), end="") + elif args.command == "reset": + if target.exists(): + target.unlink() + print(target) + else: + incoming = read(Path(args.input), True) + validate(incoming, partial=True) + updated = {"schemaVersion": 1, "isCustomized": True, "settings": {**current()["settings"], **incoming.get("settings", {})}} + validate(updated) + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(yaml.safe_dump(updated, sort_keys=False), encoding="utf-8") + print(target) + + +if __name__ == "__main__": + main() diff --git a/plugins/apple-dev-skills/skills/xcode-build-run-workflow/SKILL.md b/plugins/apple-dev-skills/skills/xcode-build-run-workflow/SKILL.md index b9f0ad9b..ee48d958 100644 --- a/plugins/apple-dev-skills/skills/xcode-build-run-workflow/SKILL.md +++ b/plugins/apple-dev-skills/skills/xcode-build-run-workflow/SKILL.md @@ -89,6 +89,7 @@ Use this skill as the primary execution workflow for non-testing work in or arou ## Fallbacks and Handoffs +- Recommend `diagnose-apple-entitlements` before editing when the failure may originate in account/profile authorization, final nested-code signing, export transformation, privacy consent, or runtime policy rather than the tracked Xcode target. - Official CLI execution is the only fallback path when the primary agent-side MCP path cannot complete. - Use `references/mcp-failure-handoff.md` for the canonical fallback and handoff payload. - Use `references/allowlist-guidance.md` when a safe official CLI fallback is blocked by local rules. diff --git a/plugins/apple-dev-skills/tests/test_app_extension_workflows.py b/plugins/apple-dev-skills/tests/test_app_extension_workflows.py index 08e01434..a83fa265 100644 --- a/plugins/apple-dev-skills/tests/test_app_extension_workflows.py +++ b/plugins/apple-dev-skills/tests/test_app_extension_workflows.py @@ -62,7 +62,7 @@ def test_inventory_and_metadata_include_the_new_skills(self) -> None: self.assertIn(f"`{skill}`", readme) self.assertIn("mailkit", manifest) self.assertIn("file-provider", manifest) - self.assertIn("Expected exactly 59 active skills", validator) + self.assertIn("Expected exactly 62 active skills", validator) if __name__ == "__main__": diff --git a/plugins/apple-dev-skills/tests/test_apple_developer_provisioning_workflow.py b/plugins/apple-dev-skills/tests/test_apple_developer_provisioning_workflow.py index dd32db5c..7fb0cd4a 100644 --- a/plugins/apple-dev-skills/tests/test_apple_developer_provisioning_workflow.py +++ b/plugins/apple-dev-skills/tests/test_apple_developer_provisioning_workflow.py @@ -55,7 +55,7 @@ def test_inventory_metadata_and_roadmap_are_updated(self) -> None: self.assertIn("apple-developer-provisioning-workflow", readme) self.assertIn("Apple Developer provisioning", plugin) self.assertIn("./skills/apple-developer-provisioning-workflow/SKILL.md", validator) - self.assertIn("Expected exactly 59 active skills", validator) + self.assertIn("Expected exactly 62 active skills", validator) self.assertIn("Milestone 54: Apple Developer Provisioning and CloudKit Workflow - Completed", roadmap) def test_customization_cli_preserves_shared_apply_and_reset_verbs(self) -> None: diff --git a/plugins/apple-dev-skills/tests/test_arkit_spatial_face_body_workflows.py b/plugins/apple-dev-skills/tests/test_arkit_spatial_face_body_workflows.py index 80d5e9af..9ea94696 100644 --- a/plugins/apple-dev-skills/tests/test_arkit_spatial_face_body_workflows.py +++ b/plugins/apple-dev-skills/tests/test_arkit_spatial_face_body_workflows.py @@ -109,7 +109,7 @@ def test_inventory_metadata_customization_and_cross_skill_handoffs_are_aligned(s ) self.assertIn("ARKit", plugin) self.assertIn("LiDAR", plugin) - self.assertIn("Expected exactly 59 active skills", validator) + self.assertIn("Expected exactly 62 active skills", validator) self.assertIn("arkit-spatial-sensing-workflow", self.read("skills/camera-capture-depth-workflow/SKILL.md")) self.assertIn("arkit-face-body-tracking-workflow", self.read("skills/vision-image-analysis-workflow/SKILL.md")) self.assertIn("arkit-spatial-sensing-workflow", self.read("skills/apple-ui-accessibility-workflow/SKILL.md")) diff --git a/plugins/apple-dev-skills/tests/test_camera_capture_depth_workflow.py b/plugins/apple-dev-skills/tests/test_camera_capture_depth_workflow.py index 2dea664f..e7c44a67 100644 --- a/plugins/apple-dev-skills/tests/test_camera_capture_depth_workflow.py +++ b/plugins/apple-dev-skills/tests/test_camera_capture_depth_workflow.py @@ -93,7 +93,7 @@ def test_inventory_metadata_customization_and_handoffs_are_aligned(self) -> None ) self.assertIn("camera", plugin.lower()) self.assertIn("depth", plugin.lower()) - self.assertIn("Expected exactly 59 active skills", validator) + self.assertIn("Expected exactly 62 active skills", validator) self.assertIn(skill, self.read("skills/avfoundation-media-pipeline-workflow/SKILL.md")) self.assertIn(skill, self.read("skills/vision-image-analysis-workflow/SKILL.md")) diff --git a/plugins/apple-dev-skills/tests/test_customization_consolidation_review.py b/plugins/apple-dev-skills/tests/test_customization_consolidation_review.py index 1b21bb08..57a0df8a 100644 --- a/plugins/apple-dev-skills/tests/test_customization_consolidation_review.py +++ b/plugins/apple-dev-skills/tests/test_customization_consolidation_review.py @@ -66,8 +66,8 @@ def test_review_doc_counts_match_live_customization_surface(self) -> None: knob_count = _count_template_knobs() runtime_enforced, policy_only = _count_statuses() - self.assertEqual(template_count, 60) - self.assertEqual(script_count, 60) + self.assertEqual(template_count, 63) + self.assertEqual(script_count, 63) self.assertEqual(knob_count, 21) self.assertEqual(runtime_enforced, 20) self.assertEqual(policy_only, 1) diff --git a/plugins/apple-dev-skills/tests/test_devicecheck_app_attest_workflow.py b/plugins/apple-dev-skills/tests/test_devicecheck_app_attest_workflow.py index 22b392d4..ca6becc4 100644 --- a/plugins/apple-dev-skills/tests/test_devicecheck_app_attest_workflow.py +++ b/plugins/apple-dev-skills/tests/test_devicecheck_app_attest_workflow.py @@ -71,7 +71,7 @@ def test_plugin_inventory_includes_devicecheck_workflow(self) -> None: self.assertIn("DeviceCheck", plugin) self.assertIn("App Attest", plugin) self.assertIn("./skills/devicecheck-app-attest-workflow/SKILL.md", validator) - self.assertIn("Expected exactly 59 active skills", validator) + self.assertIn("Expected exactly 62 active skills", validator) self.assertIn("Milestone 53: DeviceCheck and App Attest Workflow - Completed", roadmap) diff --git a/plugins/apple-dev-skills/tests/test_imaging_foundation_workflows.py b/plugins/apple-dev-skills/tests/test_imaging_foundation_workflows.py index a0d91d27..4828cd38 100644 --- a/plugins/apple-dev-skills/tests/test_imaging_foundation_workflows.py +++ b/plugins/apple-dev-skills/tests/test_imaging_foundation_workflows.py @@ -95,7 +95,7 @@ def test_inventory_metadata_and_customization_are_aligned(self) -> None: self.assertIn("Core Image", plugin) self.assertIn("Image I/O", plugin) - self.assertIn("Expected exactly 59 active skills", validator) + self.assertIn("Expected exactly 62 active skills", validator) if __name__ == "__main__": diff --git a/plugins/apple-dev-skills/tests/test_macos_platform_security_workflows.py b/plugins/apple-dev-skills/tests/test_macos_platform_security_workflows.py new file mode 100644 index 00000000..bfead0df --- /dev/null +++ b/plugins/apple-dev-skills/tests/test_macos_platform_security_workflows.py @@ -0,0 +1,67 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +def read(relative: str) -> str: + return (ROOT / relative).read_text(encoding="utf-8") + + +def test_privacy_workflow_preserves_permission_boundaries() -> None: + skill = read("skills/macos-privacy-permissions-workflow/SKILL.md") + matrix = read("skills/macos-privacy-permissions-workflow/references/permission-class-matrix.md") + reset = read("skills/macos-privacy-permissions-workflow/references/prompting-settings-reset-and-mdm.md") + attribution = read("skills/macos-privacy-permissions-workflow/references/responsible-code-and-attribution.md") + + for term in ( + "AXIsProcessTrustedWithOptions", + "AEDeterminePermissionToAutomateTarget", + "EPDeveloperTool.authorizationStatus", + "CGPreflightScreenCaptureAccess", + "Full Disk Access", + ): + assert term in matrix + assert "reset surface, not a general grant or status tool" in reset + assert "Terminal, an IDE, or an agent host" in attribution + assert "Do not edit, replace, copy back, or directly query a live TCC database" in skill + assert "explicit approval immediately before" in skill + + +def test_privacy_workflow_has_discovery_metadata() -> None: + name = "macos-privacy-permissions-workflow" + assert f"./skills/{name}/SKILL.md" in read(".github/scripts/validate_repo_docs.sh") + assert f"${name}" in read(f"skills/{name}/agents/openai.yaml") + + +def test_sandbox_file_workflow_preserves_authorization_lifetime() -> None: + skill = read("skills/macos-sandbox-file-access-workflow/SKILL.md") + lifecycle = read("skills/macos-sandbox-file-access-workflow/references/security-scoped-bookmark-lifecycle.md") + controls = read("skills/macos-sandbox-file-access-workflow/references/sandbox-and-filesystem-control-map.md") + boundaries = read("skills/macos-sandbox-file-access-workflow/references/helpers-groups-and-process-boundaries.md") + assert "startAccessingSecurityScopedResource()" in lifecycle + assert "stopAccessingSecurityScopedResource()" in lifecycle + assert "If stale" in lifecycle + for layer in ("POSIX and ACL", "App Sandbox", "TCC", "Data Vault/SIP"): + assert layer in controls + assert "Do not pass a path across IPC and assume authorization follows" in boundaries + assert "Do not claim a bookmark bypasses TCC" in skill + + +def test_entitlement_workflow_requires_five_state_evidence() -> None: + skill = read("skills/diagnose-apple-entitlements/SKILL.md") + comparison = read("skills/diagnose-apple-entitlements/references/five-state-entitlement-comparison.md") + classification = read("skills/diagnose-apple-entitlements/references/restricted-and-private-entitlements.md") + artifact = read("skills/diagnose-apple-entitlements/references/artifact-and-nested-code-inspection.md") + for state in ("Desired behavior", "Tracked source", "Account authorization", "Signed result", "Runtime result"): + assert state in comparison + assert "do not recommend them for an ordinary third-party product" in classification + assert "`codesign --deep` verification is not a substitute" in artifact + assert "Do not call an entitlement effective" in skill + + +def test_slice_two_skills_have_discovery_metadata() -> None: + validator = read(".github/scripts/validate_repo_docs.sh") + for name in ("macos-sandbox-file-access-workflow", "diagnose-apple-entitlements"): + assert f"./skills/{name}/SKILL.md" in validator + assert f"${name}" in read(f"skills/{name}/agents/openai.yaml") diff --git a/plugins/apple-dev-skills/tests/test_macos_virtualization_workflows.py b/plugins/apple-dev-skills/tests/test_macos_virtualization_workflows.py index 423a3ceb..6f166ff8 100644 --- a/plugins/apple-dev-skills/tests/test_macos_virtualization_workflows.py +++ b/plugins/apple-dev-skills/tests/test_macos_virtualization_workflows.py @@ -75,5 +75,5 @@ def test_inventory_metadata_and_customization_contracts_include_all_four() -> No assert (ROOT / "skills" / skill / "agents" / "openai.yaml").is_file() assert (ROOT / "skills" / skill / "references" / "customization.template.yaml").is_file() assert (ROOT / "skills" / skill / "scripts" / "customization_config.py").is_file() - assert "Expected exactly 59 active skills" in validator + assert "Expected exactly 62 active skills" in validator assert "virtualization-framework" in manifest diff --git a/plugins/apple-dev-skills/tests/test_photos_library_editing_workflow.py b/plugins/apple-dev-skills/tests/test_photos_library_editing_workflow.py index 268d3c71..707848bf 100644 --- a/plugins/apple-dev-skills/tests/test_photos_library_editing_workflow.py +++ b/plugins/apple-dev-skills/tests/test_photos_library_editing_workflow.py @@ -95,7 +95,7 @@ def test_no_repository_inventory_metadata_customization_and_handoffs_are_aligned ) self.assertIn("PhotosUI", plugin) self.assertIn("PhotoKit", plugin) - self.assertIn("Expected exactly 59 active skills", validator) + self.assertIn("Expected exactly 62 active skills", validator) self.assertIn(name, self.read("skills/apple-image-representation-workflow/SKILL.md")) self.assertIn(name, self.read("skills/core-image-processing-workflow/SKILL.md")) self.assertIn(name, self.read("skills/avfoundation-media-pipeline-workflow/SKILL.md")) diff --git a/plugins/apple-dev-skills/tests/test_tipkit_workflow.py b/plugins/apple-dev-skills/tests/test_tipkit_workflow.py index 1c71438b..c19e7915 100644 --- a/plugins/apple-dev-skills/tests/test_tipkit_workflow.py +++ b/plugins/apple-dev-skills/tests/test_tipkit_workflow.py @@ -52,7 +52,7 @@ def test_inventory_and_metadata_include_tipkit(self) -> None: self.assertIn("tipkit-workflow", readme) self.assertIn("TipKit", plugin) self.assertIn("./skills/tipkit-workflow/SKILL.md", validator) - self.assertIn("Expected exactly 59 active skills", validator) + self.assertIn("Expected exactly 62 active skills", validator) self.assertIn("Milestone 55: TipKit Workflow", roadmap) diff --git a/plugins/apple-dev-skills/tests/test_video_codec_processing_workflow.py b/plugins/apple-dev-skills/tests/test_video_codec_processing_workflow.py index 1944806a..ad039030 100644 --- a/plugins/apple-dev-skills/tests/test_video_codec_processing_workflow.py +++ b/plugins/apple-dev-skills/tests/test_video_codec_processing_workflow.py @@ -92,7 +92,7 @@ def test_avfoundation_preference_inventory_metadata_and_handoffs_are_aligned(sel ) self.assertIn("VideoToolbox", plugin) self.assertIn("Core Video", plugin) - self.assertIn("Expected exactly 59 active skills", validator) + self.assertIn("Expected exactly 62 active skills", validator) self.assertIn(name, self.read("skills/avfoundation-media-pipeline-workflow/SKILL.md")) self.assertIn(name, self.read("skills/coremedia-timing-samplebuffer-workflow/SKILL.md")) diff --git a/plugins/apple-dev-skills/tests/test_vision_recognition_workflows.py b/plugins/apple-dev-skills/tests/test_vision_recognition_workflows.py index 542314b8..c912a32e 100644 --- a/plugins/apple-dev-skills/tests/test_vision_recognition_workflows.py +++ b/plugins/apple-dev-skills/tests/test_vision_recognition_workflows.py @@ -89,7 +89,7 @@ def test_inventory_metadata_customization_and_handoffs_are_aligned(self) -> None ) self.assertIn("Apple Vision", plugin) self.assertIn("Core ML", plugin) - self.assertIn("Expected exactly 59 active skills", validator) + self.assertIn("Expected exactly 62 active skills", validator) if __name__ == "__main__": diff --git a/plugins/apple-dev-skills/tests/test_xcode_localization_workflow.py b/plugins/apple-dev-skills/tests/test_xcode_localization_workflow.py index 59e79637..352d902b 100644 --- a/plugins/apple-dev-skills/tests/test_xcode_localization_workflow.py +++ b/plugins/apple-dev-skills/tests/test_xcode_localization_workflow.py @@ -53,7 +53,7 @@ def test_inventory_metadata_and_roadmap_name_the_shipped_skill(self) -> None: self.assertIn("xcode-localization-workflow", text) self.assertIn("String Catalog localization", manifest) self.assertIn('"string-catalog"', manifest) - self.assertIn("Expected exactly 59 active skills", validator) + self.assertIn("Expected exactly 62 active skills", validator) if __name__ == "__main__": diff --git a/plugins/apple-dev-skills/uv.lock b/plugins/apple-dev-skills/uv.lock index 3b65a1aa..93ed97e9 100644 --- a/plugins/apple-dev-skills/uv.lock +++ b/plugins/apple-dev-skills/uv.lock @@ -4,7 +4,7 @@ requires-python = ">=3.10" [[package]] name = "apple-dev-skills-maintainer" -version = "9.20.0" +version = "9.21.0" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/cardhop-app/.codex-plugin/plugin.json b/plugins/cardhop-app/.codex-plugin/plugin.json index 7901db59..337a3057 100644 --- a/plugins/cardhop-app/.codex-plugin/plugin.json +++ b/plugins/cardhop-app/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "cardhop-app", - "version": "9.20.0", + "version": "9.21.0", "description": "Cardhop.app workflow guidance plus a bundled local MCP server for contact capture and updates on macOS.", "author": { "name": "Gale", diff --git a/plugins/cardhop-app/mcp/pyproject.toml b/plugins/cardhop-app/mcp/pyproject.toml index bf61bb89..4a7e736d 100644 --- a/plugins/cardhop-app/mcp/pyproject.toml +++ b/plugins/cardhop-app/mcp/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "cardhop-app-mcp" -version = "9.20.0" +version = "9.21.0" requires-python = ">=3.13" dependencies = [ "fastmcp>=3.0.2", diff --git a/plugins/cardhop-app/mcp/uv.lock b/plugins/cardhop-app/mcp/uv.lock index 8b7dd6d1..0c3c7b58 100644 --- a/plugins/cardhop-app/mcp/uv.lock +++ b/plugins/cardhop-app/mcp/uv.lock @@ -141,7 +141,7 @@ wheels = [ [[package]] name = "cardhop-app-mcp" -version = "9.20.0" +version = "9.21.0" source = { virtual = "." } dependencies = [ { name = "fastmcp" }, diff --git a/plugins/cloud-deployment-skills/.codex-plugin/plugin.json b/plugins/cloud-deployment-skills/.codex-plugin/plugin.json index dbbcf3c4..a2986185 100644 --- a/plugins/cloud-deployment-skills/.codex-plugin/plugin.json +++ b/plugins/cloud-deployment-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "cloud-deployment-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Codex skills for routing cloud deployment work through official provider plugins, MCP servers, CLIs, and Socket-owned deployment guidance.", "author": { "name": "Gale", diff --git a/plugins/cloud-inference-skills/.codex-plugin/plugin.json b/plugins/cloud-inference-skills/.codex-plugin/plugin.json index 3ebcd58d..c67ee646 100644 --- a/plugins/cloud-inference-skills/.codex-plugin/plugin.json +++ b/plugins/cloud-inference-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "cloud-inference-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Cloud AI inference workflow skills for routing model serving, training, conversion, and GPU infrastructure work across Runpod, Hugging Face, AWS, Vast.ai, CoreWeave, and similar providers.", "author": { "name": "Gale", diff --git a/plugins/cybersecurity-skills/.codex-plugin/plugin.json b/plugins/cybersecurity-skills/.codex-plugin/plugin.json index e3763f3e..b012feee 100644 --- a/plugins/cybersecurity-skills/.codex-plugin/plugin.json +++ b/plugins/cybersecurity-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "cybersecurity-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Defensive cybersecurity, isolated Linux and macOS analysis labs, suspicious-content and malware analysis, macOS defense, vulnerability testing, pentesting, and incident response workflows.", "skills": "./skills/", "author": { diff --git a/plugins/cybersecurity-skills/skills/assess-macos-threat/SKILL.md b/plugins/cybersecurity-skills/skills/assess-macos-threat/SKILL.md index 6be30126..ca2f4593 100644 --- a/plugins/cybersecurity-skills/skills/assess-macos-threat/SKILL.md +++ b/plugins/cybersecurity-skills/skills/assess-macos-threat/SKILL.md @@ -28,8 +28,11 @@ Read [references/macos-security-layers.md](references/macos-security-layers.md) - Separate a blocked attempt from successful execution and successful execution from compromise. 6. Assess and advise. - State classification/confidence, immediate isolation needs, evidence gaps, and the smallest next workflow. + - Route ordinary application permission implementation to `macos-privacy-permissions-workflow`; route private symbols, control internals, or exact-build Gatekeeper/XProtect/TCC questions to `research-macos-security-control`. - Do not generalize guest-observed behavior to a physical Mac when hardware, Secure Enclave, recoveryOS, kernel/system-extension, device, or anti-VM behavior remains unresolved. ## Output Return host/event identity, platform-layer evidence, artifact identity, observed behavior, assessment/confidence, immediate advice, and focused next checks. + +Do not interpret an XProtect or Gatekeeper event alone as proof that malware executed or that the host is compromised. Preserve the event type, exact OS/security-data state, actor/artifact identity, and observed behavior. diff --git a/plugins/cybersecurity-skills/skills/assess-macos-threat/references/macos-security-layers.md b/plugins/cybersecurity-skills/skills/assess-macos-threat/references/macos-security-layers.md index 2706f5e4..e88831b3 100644 --- a/plugins/cybersecurity-skills/skills/assess-macos-threat/references/macos-security-layers.md +++ b/plugins/cybersecurity-skills/skills/assess-macos-threat/references/macos-security-layers.md @@ -12,4 +12,8 @@ Keep these meanings distinct: - SIP and mandatory controls: protect system and data surfaces beyond ordinary root access; - Endpoint Security: telemetry/control API whose evidence depends on client entitlement and permissions. +Route supported application-facing TCC prompting, status, responsible-code, and Settings behavior to `apple-dev-skills:macos-privacy-permissions-workflow`. Route private TCC constants/schemas, Gatekeeper/XProtect implementation internals, and exact-build policy comparisons to `reverse-engineering-skills:research-macos-security-control`. + +An alert/event is evidence of the named control action, not automatically proof of prior execution, persistence, compromise, or complete remediation. Correlate process/file/network state and preserve telemetry coverage. + Use current [Apple Platform Security malware guidance](https://support.apple.com/guide/security/protecting-against-malware-sec469d47bd8/web). Record exact OS build because enforcement and available events change. diff --git a/plugins/cybersecurity-skills/skills/contain-and-recover-macos/SKILL.md b/plugins/cybersecurity-skills/skills/contain-and-recover-macos/SKILL.md index e6bc7a66..ef6da819 100644 --- a/plugins/cybersecurity-skills/skills/contain-and-recover-macos/SKILL.md +++ b/plugins/cybersecurity-skills/skills/contain-and-recover-macos/SKILL.md @@ -24,6 +24,7 @@ Read [references/macos-response-ladder.md](references/macos-response-ladder.md) - Never edit launchd's internal state directly. 5. Eradicate the verified mechanism. - Remove or quarantine confirmed artifacts, registrations, extensions, profiles, helpers, rules, and downloaded stages; preserve hashes and paths. + - Do not reset, disable, or weaken TCC, Gatekeeper, XProtect, SIP, App Sandbox, or another protection merely to make a suspicious artifact run or simplify removal. 6. Respond to identity exposure. - Rotate affected credentials/tokens from a trusted device, revoke sessions/keys, review MFA and recovery methods, and notify owners/providers as warranted. 7. Recover. diff --git a/plugins/cybersecurity-skills/skills/harden-macos/SKILL.md b/plugins/cybersecurity-skills/skills/harden-macos/SKILL.md index 148fd7c2..8f785aca 100644 --- a/plugins/cybersecurity-skills/skills/harden-macos/SKILL.md +++ b/plugins/cybersecurity-skills/skills/harden-macos/SKILL.md @@ -19,6 +19,7 @@ Read [references/macos-hardening-review.md](references/macos-hardening-review.md - Verify OS, rapid/security data updates, browsers, extensions, apps, and package managers from authoritative channels. 3. Preserve platform protections. - Verify Gatekeeper/XProtect automatic protection, SIP, TCC/privacy access, code-signing expectations, and sandbox/container use where applicable. + - Keep this defensive posture review separate from developer prompt/request implementation; route ordinary app permission design to `macos-privacy-permissions-workflow`. 4. Protect data and recovery. - Review FileVault/recovery ownership, screen lock, backup availability and restore testing, account separation, and secure disposal/export practices. 5. Reduce exposed services and persistence. diff --git a/plugins/cybersecurity-skills/skills/inspect-macos-runtime-activity/SKILL.md b/plugins/cybersecurity-skills/skills/inspect-macos-runtime-activity/SKILL.md index 16f3134c..b5741eb7 100644 --- a/plugins/cybersecurity-skills/skills/inspect-macos-runtime-activity/SKILL.md +++ b/plugins/cybersecurity-skills/skills/inspect-macos-runtime-activity/SKILL.md @@ -24,6 +24,7 @@ Read [references/macos-runtime-evidence.md](references/macos-runtime-evidence.md 5. Inspect focused logs/events. - Query relevant unified logs and existing Endpoint Security/XProtect/Gatekeeper evidence for the narrow time window. - Record Full Disk Access, root, Endpoint Security entitlement, or other permissions required and what absence hides. + - Treat missing collection permission or unavailable event types as a telemetry gap, not evidence that the behavior did not occur. Route app-facing permission implementation to `macos-privacy-permissions-workflow` and exact private-control interpretation to `research-macos-security-control`. 6. Build a timeline. - Separate user action, launch, child processes, file changes, prompts, network, persistence, detection, and termination. 7. Assess behavior and gaps. diff --git a/plugins/cybersecurity-skills/skills/inspect-macos-runtime-activity/references/macos-runtime-evidence.md b/plugins/cybersecurity-skills/skills/inspect-macos-runtime-activity/references/macos-runtime-evidence.md index be9909ea..6f0fff83 100644 --- a/plugins/cybersecurity-skills/skills/inspect-macos-runtime-activity/references/macos-runtime-evidence.md +++ b/plugins/cybersecurity-skills/skills/inspect-macos-runtime-activity/references/macos-runtime-evidence.md @@ -10,3 +10,5 @@ | TCC/system settings | declared or granted privacy access | grant presence does not prove use | Record failed commands and missing permissions. Do not silently substitute missing telemetry with assumptions. + +Record the exact collecting executable, permission class, approval state, event subscription, time window, filter, retention, and privacy redaction. If collection needs a supported privacy decision, hand implementation to `apple-dev-skills:macos-privacy-permissions-workflow`; do not treat granting a broad terminal or agent host as equivalent to authorizing a narrow collector. diff --git a/plugins/cybersecurity-skills/skills/prepare-isolated-analysis-lab/SKILL.md b/plugins/cybersecurity-skills/skills/prepare-isolated-analysis-lab/SKILL.md index ef15110c..c20fc0ad 100644 --- a/plugins/cybersecurity-skills/skills/prepare-isolated-analysis-lab/SKILL.md +++ b/plugins/cybersecurity-skills/skills/prepare-isolated-analysis-lab/SKILL.md @@ -52,6 +52,7 @@ Return the approved isolation decision, selected profile, trusted-base identity, - Use `perform-dynamic-malware-analysis` for controlled execution and observation. - Use Reverse Engineering skills for exported binaries, disassembly, decompilation, and symbols. +- Use `reverse-engineering-skills:research-macos-security-control` for exact-build TCC, sandbox, entitlement, Gatekeeper, XProtect, SIP, or system-policy research that needs public/private evidence separation. - Use `apple-dev-skills:virtualization-framework-workflow` for custom VM implementation defects. - Use `apple-dev-skills:macos-development-vm-workflow` or `linux-development-vm-workflow` for benign guest provisioning and lifecycle mechanics. - Return to `select-analysis-isolation` when the chosen boundary fails fidelity or containment preflight. diff --git a/plugins/cybersecurity-skills/skills/select-analysis-isolation/SKILL.md b/plugins/cybersecurity-skills/skills/select-analysis-isolation/SKILL.md index c6eb69d2..d2a7454f 100644 --- a/plugins/cybersecurity-skills/skills/select-analysis-isolation/SKILL.md +++ b/plugins/cybersecurity-skills/skills/select-analysis-isolation/SKILL.md @@ -40,6 +40,7 @@ Read [references/isolation-matrix.md](references/isolation-matrix.md) before sel 7. Hand an approved execution boundary to `prepare-isolated-analysis-lab`. - Use `apple-dev-skills:choose-macos-virtualization-shape` when the development boundary is still undecided. - Use `apple-dev-skills:virtualization-framework-workflow` when a custom macOS or Linux VM host must be implemented or diagnosed. + - Use `reverse-engineering-skills:research-macos-security-control` when the lab must preserve an exact-build public/private control comparison and technical-note contract. - Treat a SIP-enabled macOS VM as the stable high-fidelity path for SIP-sensitive behavior; local sandbox, TCC, and failure injection are explicitly lower-fidelity approximations. ## Stop Conditions diff --git a/plugins/cybersecurity-skills/tests/test_macos_security_handoffs.py b/plugins/cybersecurity-skills/tests/test_macos_security_handoffs.py new file mode 100644 index 00000000..602d52c6 --- /dev/null +++ b/plugins/cybersecurity-skills/tests/test_macos_security_handoffs.py @@ -0,0 +1,30 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +def read(relative: str) -> str: + return (ROOT / relative).read_text(encoding="utf-8") + + +def test_macos_threat_workflows_route_app_and_private_control_questions() -> None: + assess = read("skills/assess-macos-threat/SKILL.md") + runtime = read("skills/inspect-macos-runtime-activity/SKILL.md") + layers = read("skills/assess-macos-threat/references/macos-security-layers.md") + for text in (assess, runtime, layers): + assert "macos-privacy-permissions-workflow" in text + assert "research-macos-security-control" in text + assert "not automatically proof of prior execution" in layers + assert "telemetry gap, not evidence" in runtime + + +def test_hardening_recovery_and_isolation_preserve_platform_controls() -> None: + harden = read("skills/harden-macos/SKILL.md") + recover = read("skills/contain-and-recover-macos/SKILL.md") + select = read("skills/select-analysis-isolation/SKILL.md") + lab = read("skills/prepare-isolated-analysis-lab/SKILL.md") + assert "developer prompt/request implementation" in harden + assert "Do not reset, disable, or weaken TCC" in recover + assert "research-macos-security-control" in select + assert "research-macos-security-control" in lab diff --git a/plugins/dotnet-skills/.codex-plugin/plugin.json b/plugins/dotnet-skills/.codex-plugin/plugin.json index 628dfdd9..d9b6d9cf 100644 --- a/plugins/dotnet-skills/.codex-plugin/plugin.json +++ b/plugins/dotnet-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "dotnet-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Codex skills for choosing, bootstrapping, building, testing, packaging, diagnosing, and maintaining .NET projects with F# and C# as equal first-party languages.", "author": { "name": "Gale", diff --git a/plugins/game-dev-skills/.codex-plugin/plugin.json b/plugins/game-dev-skills/.codex-plugin/plugin.json index 94ae1ef2..7c974f0c 100644 --- a/plugins/game-dev-skills/.codex-plugin/plugin.json +++ b/plugins/game-dev-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "game-dev-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Apple platform game development workflow skills for native Metal rendering, Game Porting Toolkit routing, MetalFX, GPU asset streaming, neural rendering, frameworks, input, haptics, and profiling.", "author": { "name": "Gale", diff --git a/plugins/messaging-collaboration-skills/.codex-plugin/plugin.json b/plugins/messaging-collaboration-skills/.codex-plugin/plugin.json index e28d12ee..f4c76813 100644 --- a/plugins/messaging-collaboration-skills/.codex-plugin/plugin.json +++ b/plugins/messaging-collaboration-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "messaging-collaboration-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Codex workflows for chat apps, bots, collaboration, iMessage, Apple notifications and Push to Talk, VoIP, and default communication-app planning.", "author": { "name": "Gale", diff --git a/plugins/model-lab-skills/.codex-plugin/plugin.json b/plugins/model-lab-skills/.codex-plugin/plugin.json index 0e70b1e0..f247a9dc 100644 --- a/plugins/model-lab-skills/.codex-plugin/plugin.json +++ b/plugins/model-lab-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "model-lab-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Reproducible model training, evaluation, intervention, and runtime research workflows.", "author": { "name": "Gale" diff --git a/plugins/network-protocol-skills/.codex-plugin/plugin.json b/plugins/network-protocol-skills/.codex-plugin/plugin.json index e99c746e..39aba367 100644 --- a/plugins/network-protocol-skills/.codex-plugin/plugin.json +++ b/plugins/network-protocol-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "network-protocol-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Codex skills for choosing, planning, implementing, and diagnosing modern application transports and real-time networking protocols, including QUIC, HTTP/3, WebRTC, Media over QUIC, WebTransport-adjacent handoffs, protocol maturity checks, and stack-specific implementation routing.", "author": { "name": "Gale", diff --git a/plugins/productivity-skills/.codex-plugin/plugin.json b/plugins/productivity-skills/.codex-plugin/plugin.json index 266faffb..e36994ba 100644 --- a/plugins/productivity-skills/.codex-plugin/plugin.json +++ b/plugins/productivity-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "productivity-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Broadly useful productivity workflows for Codex.", "author": { "name": "Gale", diff --git a/plugins/productivity-skills/pyproject.toml b/plugins/productivity-skills/pyproject.toml index 9b3531d4..9a8e3605 100644 --- a/plugins/productivity-skills/pyproject.toml +++ b/plugins/productivity-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "productivity-skills-maintenance" -version = "9.20.0" +version = "9.21.0" description = "Maintainer-only Python tooling baseline for productivity-skills." requires-python = ">=3.11" dependencies = [] diff --git a/plugins/productivity-skills/uv.lock b/plugins/productivity-skills/uv.lock index 497b6986..d2feec5a 100644 --- a/plugins/productivity-skills/uv.lock +++ b/plugins/productivity-skills/uv.lock @@ -228,7 +228,7 @@ wheels = [ [[package]] name = "productivity-skills-maintenance" -version = "9.20.0" +version = "9.21.0" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/python-skills/.codex-plugin/plugin.json b/plugins/python-skills/.codex-plugin/plugin.json index 10a6ca0b..0234c896 100644 --- a/plugins/python-skills/.codex-plugin/plugin.json +++ b/plugins/python-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "python-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Bundled Python-focused Codex skills for uv bootstrapping, project implementation, diagnostics, packaging, tooling, CI, upgrades, FastAPI, FastMCP, and pytest workflows.", "author": { "name": "Gale", diff --git a/plugins/python-skills/pyproject.toml b/plugins/python-skills/pyproject.toml index 1ccfc127..95b9c454 100644 --- a/plugins/python-skills/pyproject.toml +++ b/plugins/python-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "python-skills-maintainer" -version = "9.20.0" +version = "9.21.0" description = "Maintainer tooling for the python-skills repository" requires-python = ">=3.11" dependencies = [] diff --git a/plugins/python-skills/uv.lock b/plugins/python-skills/uv.lock index c6383a1c..692e0e01 100644 --- a/plugins/python-skills/uv.lock +++ b/plugins/python-skills/uv.lock @@ -251,7 +251,7 @@ wheels = [ [[package]] name = "python-skills-maintainer" -version = "9.20.0" +version = "9.21.0" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/reverse-engineering-skills/.codex-plugin/plugin.json b/plugins/reverse-engineering-skills/.codex-plugin/plugin.json index 98ac0559..5c75394c 100644 --- a/plugins/reverse-engineering-skills/.codex-plugin/plugin.json +++ b/plugins/reverse-engineering-skills/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "reverse-engineering-skills", - "version": "9.20.0", - "description": "Workflow skills for reverse engineering, decompilation, disassembly, symbol, and artifact-analysis tasks.", + "version": "9.21.0", + "description": "Workflow skills for reverse engineering, decompilation, disassembly, symbols, artifact analysis, and exact-build macOS security-control research.", "skills": "./skills/", "author": { "name": "Gale", @@ -21,6 +21,10 @@ "objective-c", "mach-o", "apple-silicon", + "macos-security", + "tcc", + "gatekeeper", + "xprotect", "rizin", "cutter", "malimite", @@ -33,8 +37,8 @@ "interface": { "displayName": "Reverse Engineering Skills", "shortDescription": "Binary inspection and decompilation workflow skills.", - "longDescription": "Guidance for reverse engineering workflows across artifact triage, preservation, exact-build comparison, reproducible evidence, Apple Mach-O, Swift and Objective-C runtime metadata, symbols, signing, Apple Silicon, dyld caches, dynamic analysis, kernel and firmware research, Cutter and Rizin, Malimite, Ghidra, Hopper, Unity, .NET assemblies, IL2CPP artifacts, and generated decompiler output.", - "defaultPrompt": "Use Reverse Engineering Skills when the task centers on compiled artifacts, decompiled output, disassembly, symbols, crash logs, or binary metadata. Start by identifying the artifact shape, preserving original inputs, choosing the least confusing inspection path, and recording which tool produced each observation.", + "longDescription": "Guidance for reverse engineering workflows across artifact triage, preservation, exact-build comparison, reproducible evidence, macOS TCC, sandbox, entitlement, Gatekeeper, XProtect and system-policy research, Apple Mach-O, Swift and Objective-C runtime metadata, symbols, signing, Apple Silicon, dyld caches, dynamic analysis, kernel and firmware research, Cutter and Rizin, Malimite, Ghidra, Hopper, Unity, .NET assemblies, IL2CPP artifacts, and generated decompiler output.", + "defaultPrompt": "Use Reverse Engineering Skills when the task centers on compiled artifacts, decompiled output, disassembly, symbols, crash logs, binary metadata, or exact-build macOS security-control internals. Preserve original inputs, identify exact artifacts and builds, distinguish public contracts from private evidence and runtime observations, and record which tool produced each claim.", "developerName": "Gale", "category": "Developer Tools", "capabilities": [ diff --git a/plugins/reverse-engineering-skills/skills/audit-apple-signing-and-containment/SKILL.md b/plugins/reverse-engineering-skills/skills/audit-apple-signing-and-containment/SKILL.md index 3b56d0ce..7ee1f410 100644 --- a/plugins/reverse-engineering-skills/skills/audit-apple-signing-and-containment/SKILL.md +++ b/plugins/reverse-engineering-skills/skills/audit-apple-signing-and-containment/SKILL.md @@ -41,6 +41,7 @@ Read [references/apple-signing-and-containment.md](references/apple-signing-and- - Treat the transformed copy as a new behavioral artifact and never attribute its result to the original signature. 8. Route ordinary app signing, provisioning, notarization, or distribution work to `apple-dev-skills` after the artifact audit is complete. + - Route private entitlement enforcement, TCC/sandbox attribution, Gatekeeper/XProtect internals, or other exact-build control questions to `research-macos-security-control` with this signature record. ## Guardrails diff --git a/plugins/reverse-engineering-skills/skills/evidence-notes-workflow/SKILL.md b/plugins/reverse-engineering-skills/skills/evidence-notes-workflow/SKILL.md index e952df9e..a5a92237 100644 --- a/plugins/reverse-engineering-skills/skills/evidence-notes-workflow/SKILL.md +++ b/plugins/reverse-engineering-skills/skills/evidence-notes-workflow/SKILL.md @@ -41,6 +41,7 @@ Use this skill when reverse-engineering work needs a durable notes file, handoff - Summarize the most useful confirmed findings. - List blocked or uncertain areas. - Name the next artifact, tool, command, or owner skill to use. + - Use `research-macos-security-control` when the handoff must turn exact-build macOS public/private control evidence into a bounded technical note. ## Notes Template diff --git a/plugins/reverse-engineering-skills/skills/perform-apple-dynamic-analysis/SKILL.md b/plugins/reverse-engineering-skills/skills/perform-apple-dynamic-analysis/SKILL.md index eee25b98..744d4ac6 100644 --- a/plugins/reverse-engineering-skills/skills/perform-apple-dynamic-analysis/SKILL.md +++ b/plugins/reverse-engineering-skills/skills/perform-apple-dynamic-analysis/SKILL.md @@ -41,6 +41,7 @@ Read [references/apple-dynamic-analysis.md](references/apple-dynamic-analysis.md - Preserve environment-specific limitations. 8. Hand ordinary Xcode debugging, test authoring, app fixes, or Instruments development profiling to `apple-dev-skills` after the artifact-analysis question is resolved. + - Hand a bounded runtime observation about TCC, App Sandbox, entitlements, Gatekeeper, XProtect, SIP, or another macOS policy control to `research-macos-security-control` so it remains tied to the exact build and public/private evidence hierarchy. ## Guardrails diff --git a/plugins/reverse-engineering-skills/skills/report-apple-security-research/SKILL.md b/plugins/reverse-engineering-skills/skills/report-apple-security-research/SKILL.md index 1dc4f8c5..a9b90b99 100644 --- a/plugins/reverse-engineering-skills/skills/report-apple-security-research/SKILL.md +++ b/plugins/reverse-engineering-skills/skills/report-apple-security-research/SKILL.md @@ -11,6 +11,8 @@ Write the technical evidence first and keep disclosure or program submission as Read [references/apple-security-reporting.md](references/apple-security-reporting.md) for the evidence checklist, version language, privacy checks, and live Apple sources. +Use `research-macos-security-control` first when the finding depends on exact-build TCC, sandbox, entitlement, Gatekeeper, XProtect, SIP, or system-policy implementation evidence that has not yet been separated from the supported public contract. + ## Workflow 1. Define the finding. diff --git a/plugins/reverse-engineering-skills/skills/research-macos-security-control/SKILL.md b/plugins/reverse-engineering-skills/skills/research-macos-security-control/SKILL.md new file mode 100644 index 00000000..14b713d0 --- /dev/null +++ b/plugins/reverse-engineering-skills/skills/research-macos-security-control/SKILL.md @@ -0,0 +1,57 @@ +--- +name: research-macos-security-control +description: Research one macOS security control on an exact build, separating public contracts, private evidence, and hypotheses. Use for TCC, sandbox, entitlements, Gatekeeper, XProtect, Hardened Runtime, SIP, or system-policy changes. +--- + +# Research macOS Security Control + +## Overview + +Answer one narrow control question on named artifacts and exact macOS builds. Start from supported public behavior, preserve originals, and label private symbols, schemas, strings, logs, and observed behavior as implementation evidence rather than stable API. + +## Workflow + +1. State the question and decision. + - Name the control, suspected behavior, affected actor/target, smallest falsifiable claim, expected decision, and stop condition. +2. Establish the evidence hierarchy. + - Read [references/source-and-evidence-hierarchy.md](references/source-and-evidence-hierarchy.md). + - Search Apple Platform Security, deployment/developer documentation, current SDK declarations, tool man pages, and checked-in source before private implementation. +3. Fix the environment and artifacts. + - Record hardware/architecture, exact macOS version/build, security-data/update state, selected SDK/Xcode, device management, host/guest/physical context, SIP/boot policy when relevant, and every artifact's path, hash/UUID, signing identity, acquisition source, and transformation history. +4. Classify the control. + - Use [references/control-research-matrix.md](references/control-research-matrix.md) to keep TCC, App Sandbox, entitlements, execution/distribution policy, malware protection, and system integrity distinct. +5. Inspect exact-build implementation without changing originals. + - Inspect relevant binaries/frameworks/services, Mach-O metadata, signatures/entitlements, dependencies, strings, symbols, XPC/interface metadata, launch/service ownership, focused unified logs, and existing Endpoint Security evidence. + - Use `evidence-notes-workflow`, `audit-apple-signing-and-containment`, and `compare-binary-versions` for their owned records. +6. Design the least invasive probe. + - Follow [references/exact-build-probe-design.md](references/exact-build-probe-design.md). Prefer a read-only/static check, then a bounded supported observation, then a disposable SIP-enabled guest. Require explicit approval for visible prompts, live-host permission mutations, re-signing, patching, protection changes, or sensitive capture. +7. Execute and preserve results. + - Record exact commands/tools/versions, inputs, timestamps, status/error/log fields, negative results and telemetry gaps, transformations, cleanup, and whether the observation occurred on host, guest, or physical Mac. +8. Compare builds correctly. + - Match architecture, artifact identity, security state, and analysis method. Say `changed between A and B` unless intermediate builds establish a tighter bound; do not infer causality from a symbol/string delta alone. +9. Write the technical note. + - Use [references/technical-note-contract.md](references/technical-note-contract.md). Separate public contract, direct observation, private evidence, hypothesis, conclusion/confidence, disproven explanations, and unresolved questions. +10. Route the result. + - Hand ordinary app privacy, file access, entitlement/provisioning, distribution, threat response, or formal reporting to the existing owning skill with the exact-build evidence record. + +## Guardrails + +- Do not present private symbols, `kTCCService*` constants, database schemas, log strings, sandbox profiles, or daemon behavior as supported public API. +- Do not mutate live TCC or system-policy databases for convenience. +- Do not disable SIP, boot protections, Gatekeeper, XProtect, or other controls without a separate exact goal, minimum necessary change, recorded before/after state, rollback, and explicit approval. +- Do not generalize one build, VM, architecture, security-data version, or transformed artifact to another without comparison evidence. +- Preserve originals and treat every extraction, thinning, re-sign, patch, or copy with changed metadata as a distinct artifact. +- Absence of a log/event is not proof that behavior did not occur when collection permission, retention, filter, or telemetry coverage is incomplete. + +## Output + +Return a technical note containing question/decision, public contract, environment and artifact identity, method/tooling, direct observations, private implementation evidence, hypotheses/tests, conclusions/confidence, build bounds, disproven explanations, mutations/rollback, fidelity gaps, and the next owning workflow. + +## Handoffs + +- `macos-privacy-permissions-workflow`: supported app-facing privacy implementation and responsible-code diagnosis. +- `macos-sandbox-file-access-workflow`: containers, user selection, bookmarks, App Groups, and supported persistent file access. +- `diagnose-apple-entitlements`: source/profile/signed/runtime comparison for ordinary products. +- `macos-distribution-workflow`: Gatekeeper/notarization/Hardened Runtime repair for exported products. +- `assess-macos-threat`, `inspect-macos-runtime-activity`, or `contain-and-recover-macos`: suspicious-host defensive work. +- `report-apple-security-research`: a formal reproducible security report after the technical finding exists. diff --git a/plugins/reverse-engineering-skills/skills/research-macos-security-control/agents/openai.yaml b/plugins/reverse-engineering-skills/skills/research-macos-security-control/agents/openai.yaml new file mode 100644 index 00000000..f8131f09 --- /dev/null +++ b/plugins/reverse-engineering-skills/skills/research-macos-security-control/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Research macOS Security Control" + short_description: "Research one macOS control on an exact build" + default_prompt: "Use $research-macos-security-control to produce an exact-build technical note for this security control." diff --git a/plugins/reverse-engineering-skills/skills/research-macos-security-control/references/control-research-matrix.md b/plugins/reverse-engineering-skills/skills/research-macos-security-control/references/control-research-matrix.md new file mode 100644 index 00000000..fd054a4b --- /dev/null +++ b/plugins/reverse-engineering-skills/skills/research-macos-security-control/references/control-research-matrix.md @@ -0,0 +1,12 @@ +# macOS Security Control Research Matrix + +| Control family | Public contract first | Private/exact-build evidence | Common confusion | +| --- | --- | --- | --- | +| TCC/privacy | Framework status/request APIs, System Settings, PPPC | TCC frameworks/services, attribution chains, private constants, schemas, logs | Usage description or entitlement is not consent; reset is not grant | +| App Sandbox/files | Container, documented entitlements, user selection, bookmarks | Seatbelt profiles/extensions, sandboxd/log behavior | Bookmark/path is not blanket access; TCC and mandatory controls remain | +| Entitlements/capabilities | Apple entitlement docs, account/profile rules | Private keys, platform-binary context, service checks | Signed declaration is not runtime authorization | +| Execution/distribution | Quarantine/provenance, signing, notarization, Gatekeeper, `syspolicy_check`/assessment docs | ExecutionPolicy/system-policy services, rule/evaluation internals | Gatekeeper, Hardened Runtime, Developer Tools, and malware response are distinct | +| Malware protection | Apple Platform Security, XProtect/update/Endpoint Security documentation | XProtect artifacts/config, remediation services, exact events/logs | Detection/block/remediation evidence does not alone prove execution or compromise | +| System integrity | SIP, signed system volume, recovery/boot security, system extensions | platform-binary policy, Data Vault enforcement, boot/service internals | Root/admin does not bypass mandatory controls | + +Also record cross-cutting identity (path, signer, Team ID, designated requirement, parent/helper), hardware/architecture, security-data version, management state, and artifact transformations. Use `syspolicy_check distribution` only for its documented assessment purpose and record tool output/version; do not conflate its combined checks into one root cause. diff --git a/plugins/reverse-engineering-skills/skills/research-macos-security-control/references/exact-build-probe-design.md b/plugins/reverse-engineering-skills/skills/research-macos-security-control/references/exact-build-probe-design.md new file mode 100644 index 00000000..b05b315d --- /dev/null +++ b/plugins/reverse-engineering-skills/skills/research-macos-security-control/references/exact-build-probe-design.md @@ -0,0 +1,17 @@ +# Exact-Build Probe Design + +## Probe ladder + +1. Static/read-only: documentation, SDK, signature/entitlements, Mach-O/dyld metadata, symbols, strings, interface metadata, service ownership, existing logs. +2. Supported bounded observation: public preflight/status, one benign operation, focused log query, existing Endpoint Security telemetry. +3. Disposable SIP-enabled macOS guest: prompts, quarantine/Gatekeeper, signing identity, policy state, service restart, or repeatable failure injection. +4. Physical Mac or specialized environment: Secure Enclave, recoveryOS/boot policy, hardware, system/kernel extension, anti-VM, device, or customer-fidelity questions. +5. Explicitly approved transformation/protection change: only if lower steps cannot answer the narrow hypothesis. + +## Design record + +State the hypothesis, independent/dependent variables, exact actor/target/artifact/build, baseline, one intended change, expected confirming and contradicting result, required permission/telemetry, stop condition, cleanup, and fidelity limit. Preserve negative results with collection coverage. + +Do not prompt or mutate Gale's active Mac without immediate explicit approval. Do not use a broad terminal/agent Full Disk Access grant when a narrow signed fixture can answer the question. If a guest cannot reproduce hardware, boot, recovery, Data Vault, anti-VM, or customer state, label the result lower fidelity rather than compensating with stronger host mutations. + +For cross-build work, hold architecture, artifact role, signing class, security state, analysis tools, and probe method constant. Use `compare-binary-versions` to record correspondence and temporal bounds. diff --git a/plugins/reverse-engineering-skills/skills/research-macos-security-control/references/source-and-evidence-hierarchy.md b/plugins/reverse-engineering-skills/skills/research-macos-security-control/references/source-and-evidence-hierarchy.md new file mode 100644 index 00000000..70e951da --- /dev/null +++ b/plugins/reverse-engineering-skills/skills/research-macos-security-control/references/source-and-evidence-hierarchy.md @@ -0,0 +1,14 @@ +# Source And Evidence Hierarchy + +Use the strongest applicable source and label its scope. + +1. Current Apple Platform Security, deployment, developer, support, and tool documentation. +2. Selected local SDK headers/module interfaces, command man pages/help, and Apple-open-source material for the exact release when available. +3. Exact-build original binaries/frameworks/services, code signatures, entitlements, provisioning, Mach-O/dyld metadata, exported symbols, and interface metadata. +4. Focused runtime observations, unified logs, Endpoint Security events, process ancestry, file/network effects, and exact errors from the recorded environment. +5. Matched cross-build comparison. +6. Hypothesis/inference supported by the above. + +Public documentation describes the supported contract but may omit implementation. SDK presence does not prove deployment availability. A private symbol or schema proves only that the recorded artifact contains it. A runtime success/failure proves only the recorded operation, artifact, identity, and environment. Multiple agreeing private observations strengthen a hypothesis but do not create a supported API. + +For each claim, cite the artifact/source and date/build. Keep copied excerpts minimal and preserve commands or exported metadata needed to reproduce the observation. diff --git a/plugins/reverse-engineering-skills/skills/research-macos-security-control/references/technical-note-contract.md b/plugins/reverse-engineering-skills/skills/research-macos-security-control/references/technical-note-contract.md new file mode 100644 index 00000000..db7e28f7 --- /dev/null +++ b/plugins/reverse-engineering-skills/skills/research-macos-security-control/references/technical-note-contract.md @@ -0,0 +1,56 @@ +# macOS Security Control Technical Note Contract + +```markdown +# : + +## Decision Sought +- Question: +- Why it matters: +- Stop condition: + +## Environment +| Field | Value | +| --- | --- | +| Hardware / architecture | | +| macOS version / build | | +| SDK / Xcode | | +| Security update / management state | | +| Host, guest, or physical fidelity | | +| SIP / boot policy when relevant | | + +## Artifact Identity +| Artifact | Role | Hash / UUID | Signer / requirement | Source / transformation | +| --- | --- | --- | --- | --- | + +## Public Contract +- Apple/SDK source and dated behavior: + +## Method +- Tools and versions: +- Commands/probe: +- Permissions and telemetry coverage: +- Mutations, approval, rollback: + +## Direct Observations +- ... + +## Private Implementation Evidence +- ... (exact artifact/build; not public API) + +## Hypotheses And Tests +| Hypothesis | Test | Result | Status | +| --- | --- | --- | --- | + +## Conclusions +- Conclusion and confidence: +- Disproven explanations: +- Build/version bound: + +## Unresolved Questions And Fidelity Gaps +- ... + +## Handoff +- Owning workflow and next validation: +``` + +Use `evidence-notes-workflow` records for detailed session artifacts. Never merge observation and inference into one bullet. Say `not observed with recorded coverage` instead of `did not happen` when telemetry is incomplete. diff --git a/plugins/reverse-engineering-skills/tests/test_research_macos_security_control.py b/plugins/reverse-engineering-skills/tests/test_research_macos_security_control.py new file mode 100644 index 00000000..0f158422 --- /dev/null +++ b/plugins/reverse-engineering-skills/tests/test_research_macos_security_control.py @@ -0,0 +1,33 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +def read(relative: str) -> str: + return (ROOT / relative).read_text(encoding="utf-8") + + +def test_research_workflow_separates_public_private_and_runtime_evidence() -> None: + skill = read("skills/research-macos-security-control/SKILL.md") + hierarchy = read("skills/research-macos-security-control/references/source-and-evidence-hierarchy.md") + matrix = read("skills/research-macos-security-control/references/control-research-matrix.md") + note = read("skills/research-macos-security-control/references/technical-note-contract.md") + + assert "Do not present private symbols" in skill + assert "exact macOS version/build" in skill + assert "A private symbol or schema proves only" in hierarchy + for control in ("TCC/privacy", "App Sandbox/files", "Execution/distribution", "Malware protection", "System integrity"): + assert control in matrix + for heading in ("Public Contract", "Direct Observations", "Private Implementation Evidence", "Hypotheses And Tests"): + assert heading in note + + +def test_research_workflow_requires_bounded_probe_and_handoffs() -> None: + probe = read("skills/research-macos-security-control/references/exact-build-probe-design.md") + skill = read("skills/research-macos-security-control/SKILL.md") + assert "Disposable SIP-enabled macOS guest" in probe + assert "Do not prompt or mutate Gale's active Mac" in probe + for owner in ("macos-privacy-permissions-workflow", "diagnose-apple-entitlements", "assess-macos-threat"): + assert owner in skill + assert "$research-macos-security-control" in read("skills/research-macos-security-control/agents/openai.yaml") diff --git a/plugins/rust-skills/.codex-plugin/plugin.json b/plugins/rust-skills/.codex-plugin/plugin.json index 68c1a6f9..35945208 100644 --- a/plugins/rust-skills/.codex-plugin/plugin.json +++ b/plugins/rust-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "rust-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Rust, Cargo, rustup, crate, workspace, CLI, library, package, CI, testing, linting, and formatting workflow skills.", "skills": "./skills/", "author": { diff --git a/plugins/server-side-jvm/.codex-plugin/plugin.json b/plugins/server-side-jvm/.codex-plugin/plugin.json index 51b17bb1..12f72702 100644 --- a/plugins/server-side-jvm/.codex-plugin/plugin.json +++ b/plugins/server-side-jvm/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "server-side-jvm", - "version": "9.20.0", + "version": "9.21.0", "description": "Codex skills for choosing, building, testing, and maintaining server-side JVM backend projects with Java and Scala as equal first-party languages and future Clojure support planned.", "author": { "name": "Gale", diff --git a/plugins/server-side-swift/.codex-plugin/plugin.json b/plugins/server-side-swift/.codex-plugin/plugin.json index 5e2b246f..5f0da906 100644 --- a/plugins/server-side-swift/.codex-plugin/plugin.json +++ b/plugins/server-side-swift/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "server-side-swift", - "version": "9.20.0", + "version": "9.21.0", "description": "Codex skills for bootstrapping, syncing, building, running, containerizing, deploying, and maintaining server-side Swift services, including Vapor, Hummingbird, hb, persistence, Swift OpenAPI, RPC-fit decisions, SwiftNIO, observability, auth, app sync, Docker, Apple Containerization, Fly.io, and SwiftPM-first workflows.", "author": { "name": "Gale", diff --git a/plugins/spotify/.codex-plugin/plugin.json b/plugins/spotify/.codex-plugin/plugin.json index 85940278..eb0fef94 100644 --- a/plugins/spotify/.codex-plugin/plugin.json +++ b/plugins/spotify/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "spotify", - "version": "9.20.0", + "version": "9.21.0", "description": "Placeholder plugin repository for future Spotify-focused Codex workflows.", "author": { "name": "Gale", diff --git a/plugins/swift-lang/.codex-plugin/plugin.json b/plugins/swift-lang/.codex-plugin/plugin.json index 3cee5ccc..bf30c46d 100644 --- a/plugins/swift-lang/.codex-plugin/plugin.json +++ b/plugins/swift-lang/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "swift-lang", - "version": "9.20.0", + "version": "9.21.0", "description": "Shared Swift language and tooling skills for API style, errors, functional pipelines, formatting, source organization, SwiftSyntax, compiler inspection, SourceKit, indexing, SourceKit-LSP, and modernization.", "skills": "./skills/", "author": { diff --git a/plugins/swiftasb-skills/.codex-plugin/plugin.json b/plugins/swiftasb-skills/.codex-plugin/plugin.json index 4d4b775d..dc8144d7 100644 --- a/plugins/swiftasb-skills/.codex-plugin/plugin.json +++ b/plugins/swiftasb-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "swiftasb-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Codex skills for explaining SwiftASB and building SwiftUI, AppKit, and Swift package integrations on top of it.", "author": { "name": "Gale", diff --git a/plugins/things-app/.codex-plugin/plugin.json b/plugins/things-app/.codex-plugin/plugin.json index 23a0638b..dca49f25 100644 --- a/plugins/things-app/.codex-plugin/plugin.json +++ b/plugins/things-app/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "things-app", - "version": "9.20.0", + "version": "9.21.0", "description": "Things.app skills and a bundled local MCP server for reminders, planning digests, and structured task workflows.", "author": { "name": "Gale", diff --git a/plugins/things-app/mcp/pyproject.toml b/plugins/things-app/mcp/pyproject.toml index 91f894d1..a44832f7 100644 --- a/plugins/things-app/mcp/pyproject.toml +++ b/plugins/things-app/mcp/pyproject.toml @@ -7,7 +7,7 @@ packages = ["app"] [project] name = "things-mcp" -version = "9.20.0" +version = "9.21.0" requires-python = ">=3.13" dependencies = [ "fastmcp>=3.0.2", diff --git a/plugins/things-app/mcp/uv.lock b/plugins/things-app/mcp/uv.lock index bd56b032..9c9b7377 100644 --- a/plugins/things-app/mcp/uv.lock +++ b/plugins/things-app/mcp/uv.lock @@ -1244,7 +1244,7 @@ wheels = [ [[package]] name = "things-mcp" -version = "9.20.0" +version = "9.21.0" source = { editable = "." } dependencies = [ { name = "fastmcp" }, diff --git a/plugins/things-app/pyproject.toml b/plugins/things-app/pyproject.toml index ab2be429..55d9717f 100644 --- a/plugins/things-app/pyproject.toml +++ b/plugins/things-app/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "things-app-maintenance" -version = "9.20.0" +version = "9.21.0" description = "Maintainer-only Python tooling baseline for things-app skills and plugin packaging." requires-python = ">=3.11" dependencies = [] diff --git a/plugins/things-app/uv.lock b/plugins/things-app/uv.lock index 6ffc2006..8b3f982b 100644 --- a/plugins/things-app/uv.lock +++ b/plugins/things-app/uv.lock @@ -120,7 +120,7 @@ wheels = [ [[package]] name = "things-app-maintenance" -version = "9.20.0" +version = "9.21.0" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/web-dev-skills/.codex-plugin/plugin.json b/plugins/web-dev-skills/.codex-plugin/plugin.json index b397d38a..a20140ec 100644 --- a/plugins/web-dev-skills/.codex-plugin/plugin.json +++ b/plugins/web-dev-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "web-dev-skills", - "version": "9.20.0", + "version": "9.21.0", "description": "Codex skills for focused web and Expo native-boundary workflows.", "author": { "name": "Gale", diff --git a/pyproject.toml b/pyproject.toml index d9701b97..17439945 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "socket-maintenance" -version = "9.20.0" +version = "9.21.0" description = "Root uv tooling baseline for the socket superproject." requires-python = ">=3.11" dependencies = [] diff --git a/scripts/export_hermes_skills.py b/scripts/export_hermes_skills.py index c6fe0481..fb203643 100644 --- a/scripts/export_hermes_skills.py +++ b/scripts/export_hermes_skills.py @@ -49,10 +49,13 @@ ) APPLE_SKILLS = ( "app-extension-architecture-workflow", + "diagnose-apple-entitlements", "choose-macos-virtualization-shape", "virtualization-framework-workflow", "linux-development-vm-workflow", "macos-development-vm-workflow", + "macos-privacy-permissions-workflow", + "macos-sandbox-file-access-workflow", "mailkit-workflow", "file-provider-and-finder-sync-workflow", "safari-mcp-workflow", @@ -96,6 +99,7 @@ ) REVERSE_ENGINEERING_SKILLS = ( "connect-hopper-mcp", + "research-macos-security-control", "script-hopper-analysis", "use-ghidra", "use-hopper", diff --git a/skills.sh.json b/skills.sh.json index 01b293fc..526a950d 100644 --- a/skills.sh.json +++ b/skills.sh.json @@ -34,10 +34,13 @@ "title": "Apple Dev Skills", "skills": [ "app-extension-architecture-workflow", + "diagnose-apple-entitlements", "choose-macos-virtualization-shape", "virtualization-framework-workflow", "linux-development-vm-workflow", "macos-development-vm-workflow", + "macos-privacy-permissions-workflow", + "macos-sandbox-file-access-workflow", "mailkit-workflow", "file-provider-and-finder-sync-workflow", "safari-mcp-workflow", @@ -90,6 +93,7 @@ "title": "Reverse Engineering Skills", "skills": [ "connect-hopper-mcp", + "research-macos-security-control", "script-hopper-analysis", "use-ghidra", "use-hopper" diff --git a/skills/app-extension-architecture-workflow/SKILL.md b/skills/app-extension-architecture-workflow/SKILL.md index 845759fb..549d8fcc 100644 --- a/skills/app-extension-architecture-workflow/SKILL.md +++ b/skills/app-extension-architecture-workflow/SKILL.md @@ -96,6 +96,8 @@ It owns extension-point routing, target and process boundaries, activation, enti ## Fallbacks and Handoffs +- Recommend `macos-sandbox-file-access-workflow` for user-selected files, security-scoped bookmarks, shared-container access lifetime, and file authorization across an extension process boundary. +- Recommend `diagnose-apple-entitlements` when an extension/helper capability differs between tracked source, profile authorization, final nested signature, and runtime behavior. - Recommend `mailkit-workflow` for the macOS Mail extension point and its handler contracts. - Recommend `file-provider-and-finder-sync-workflow` for remote-storage sync or Finder-only integrations. - Recommend `safari-extension-control-workflow` for Safari-specific extension choices. diff --git a/skills/assess-macos-threat/SKILL.md b/skills/assess-macos-threat/SKILL.md index 6be30126..ca2f4593 100644 --- a/skills/assess-macos-threat/SKILL.md +++ b/skills/assess-macos-threat/SKILL.md @@ -28,8 +28,11 @@ Read [references/macos-security-layers.md](references/macos-security-layers.md) - Separate a blocked attempt from successful execution and successful execution from compromise. 6. Assess and advise. - State classification/confidence, immediate isolation needs, evidence gaps, and the smallest next workflow. + - Route ordinary application permission implementation to `macos-privacy-permissions-workflow`; route private symbols, control internals, or exact-build Gatekeeper/XProtect/TCC questions to `research-macos-security-control`. - Do not generalize guest-observed behavior to a physical Mac when hardware, Secure Enclave, recoveryOS, kernel/system-extension, device, or anti-VM behavior remains unresolved. ## Output Return host/event identity, platform-layer evidence, artifact identity, observed behavior, assessment/confidence, immediate advice, and focused next checks. + +Do not interpret an XProtect or Gatekeeper event alone as proof that malware executed or that the host is compromised. Preserve the event type, exact OS/security-data state, actor/artifact identity, and observed behavior. diff --git a/skills/assess-macos-threat/references/macos-security-layers.md b/skills/assess-macos-threat/references/macos-security-layers.md index 2706f5e4..e88831b3 100644 --- a/skills/assess-macos-threat/references/macos-security-layers.md +++ b/skills/assess-macos-threat/references/macos-security-layers.md @@ -12,4 +12,8 @@ Keep these meanings distinct: - SIP and mandatory controls: protect system and data surfaces beyond ordinary root access; - Endpoint Security: telemetry/control API whose evidence depends on client entitlement and permissions. +Route supported application-facing TCC prompting, status, responsible-code, and Settings behavior to `apple-dev-skills:macos-privacy-permissions-workflow`. Route private TCC constants/schemas, Gatekeeper/XProtect implementation internals, and exact-build policy comparisons to `reverse-engineering-skills:research-macos-security-control`. + +An alert/event is evidence of the named control action, not automatically proof of prior execution, persistence, compromise, or complete remediation. Correlate process/file/network state and preserve telemetry coverage. + Use current [Apple Platform Security malware guidance](https://support.apple.com/guide/security/protecting-against-malware-sec469d47bd8/web). Record exact OS build because enforcement and available events change. diff --git a/skills/contain-and-recover-macos/SKILL.md b/skills/contain-and-recover-macos/SKILL.md index e6bc7a66..ef6da819 100644 --- a/skills/contain-and-recover-macos/SKILL.md +++ b/skills/contain-and-recover-macos/SKILL.md @@ -24,6 +24,7 @@ Read [references/macos-response-ladder.md](references/macos-response-ladder.md) - Never edit launchd's internal state directly. 5. Eradicate the verified mechanism. - Remove or quarantine confirmed artifacts, registrations, extensions, profiles, helpers, rules, and downloaded stages; preserve hashes and paths. + - Do not reset, disable, or weaken TCC, Gatekeeper, XProtect, SIP, App Sandbox, or another protection merely to make a suspicious artifact run or simplify removal. 6. Respond to identity exposure. - Rotate affected credentials/tokens from a trusted device, revoke sessions/keys, review MFA and recovery methods, and notify owners/providers as warranted. 7. Recover. diff --git a/skills/diagnose-apple-entitlements/SKILL.md b/skills/diagnose-apple-entitlements/SKILL.md new file mode 100644 index 00000000..ba3f92cc --- /dev/null +++ b/skills/diagnose-apple-entitlements/SKILL.md @@ -0,0 +1,73 @@ +--- +name: diagnose-apple-entitlements +description: Trace Apple entitlements across project source, account/profile authorization, final signed main or nested code, and runtime policy or consent. Use for missing or rejected entitlements, export-only failures, helpers, and re-signing. +--- + +# Diagnose Apple Entitlements + +## Purpose + +Trace one desired behavior through tracked project source, developer-account/profile authorization, the final signed artifact and all nested code, and the observed runtime result. Identify the owner that must change without treating an entitlement as user consent or successful access. + +## When To Use + +- Use for capability/entitlement/profile mismatches, export-only failures, nested-code differences, restricted entitlement questions, and re-signed artifacts. +- Use before editing project settings when the actual owner could be the developer account, profile, signer, export transform, runtime policy, or user decision. +- Do not use to invent or recommend private entitlements for ordinary third-party products. + +## Single-Path Workflow + +1. Define the desired operation, target, platform/OS, distribution channel, artifact, and exact runtime error. Apply the Apple docs gate through `explore-apple-swift-docs` and establish whether current Apple documentation requires or permits the capability. +2. Create the five-state record in `references/five-state-entitlement-comparison.md`: desired behavior, tracked source, account/profile authorization, signed result, and runtime result. +3. Inspect tracked source: Xcode capability, `.entitlements`, Info.plist usage description, build settings, target membership, helper/extension/XPC configuration, generated-project source, configuration, and archive/export settings. +4. Inspect account authorization: Team/App ID, capability enablement, restricted-entitlement approval, certificate, provisioning profile entitlements, environment/device scope, and whether the change is portal-only or API-supported. +5. Treat the actual built/exported artifact as source of truth for signed state. Follow `references/artifact-and-nested-code-inspection.md` for the main executable, helpers, extensions, XPC services, frameworks, daemons/tools, and embedded profiles. +6. Compare exact keys and values. Preserve public, restricted, private/undocumented, development-only, environment, and exception classifications only when supported by current evidence. Read `references/restricted-and-private-entitlements.md`. +7. Evaluate runtime controls separately: App Sandbox, Hardened Runtime, library validation, TCC/user consent, service authorization, Gatekeeper/notarization, Data Vault/SIP/platform policy, and responsible process identity. +8. If the artifact was re-signed, patched, exported differently, or otherwise transformed, record a new artifact identity and invalidate assumptions about the original signature/notarization behavior. +9. Classify the mismatch and select exactly one next owner using `references/routing-and-validation.md`. Make the source/account/build change through that owner's workflow, rebuild/export, and repeat the signed and runtime comparisons. +10. Report every state, exact mismatch, owner, evidence/confidence, validation result, and what remains unproven. + +## Inputs + +- desired behavior, target/platform/OS, distribution channel, artifact, and exact error +- project/capability source, build settings, entitlements, Info.plist, and target graph +- Team/App ID/profile/certificate/approval context +- signed main and nested artifacts, embedded profiles, transformations, and runtime environment + +## Outputs + +- five-state entitlement comparison with exact key/value differences +- entitlement classification and responsible owner +- minimum correction/rebuild/export path +- final signed-artifact and runtime validation result with remaining uncertainty + +## Guards and Stop Conditions + +- Do not invent entitlement keys, values, availability, restricted approval, or profile support. +- Do not hand-edit generated project/profile artifacts or casually re-sign a bundle to hide a source mismatch. +- Do not call an entitlement effective until the final responsible executable and required runtime operation are checked. +- Do not confuse a usage description, capability, entitlement, sandbox exception, profile allowance, or user consent. +- Stop when the actual artifact or responsible nested executable is unavailable; report source-only conclusions as unverified. + +## Fallbacks and Handoffs + +- Use `apple-developer-provisioning-workflow` for App ID, capability, certificate, profile, or account-side changes. +- Use Xcode project/build workflows for tracked capability, target, signing, archive, and export changes. +- Use `macos-distribution-workflow` for Hardened Runtime, nested signing, Gatekeeper, notarization, and stapling. +- Use `macos-privacy-permissions-workflow` for user or managed privacy authorization. +- Use `audit-apple-signing-and-containment` for forensic artifact audit and `research-macos-security-control` for private entitlement or exact-build enforcement research. + +## Customization + +Use `references/customization-flow.md`. The workflow has no runtime knobs; comparison states and evidence levels may not be skipped. + +## References + +- `references/five-state-entitlement-comparison.md` +- `references/restricted-and-private-entitlements.md` +- `references/artifact-and-nested-code-inspection.md` +- `references/routing-and-validation.md` +- Recommend `references/snippets/apple-xcode-project-core.md` when the correction belongs to an Xcode target or build configuration. +- [Entitlements](https://developer.apple.com/documentation/bundleresources/entitlements) +- [Diagnosing issues with entitlements](https://developer.apple.com/documentation/bundleresources/diagnosing-issues-with-entitlements) diff --git a/skills/diagnose-apple-entitlements/agents/openai.yaml b/skills/diagnose-apple-entitlements/agents/openai.yaml new file mode 100644 index 00000000..9f6f9953 --- /dev/null +++ b/skills/diagnose-apple-entitlements/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Diagnose Apple Entitlements" + short_description: "Trace entitlement state from source to runtime" + default_prompt: "Use $diagnose-apple-entitlements to trace this capability failure from source through runtime." diff --git a/skills/diagnose-apple-entitlements/references/artifact-and-nested-code-inspection.md b/skills/diagnose-apple-entitlements/references/artifact-and-nested-code-inspection.md new file mode 100644 index 00000000..b66cdf55 --- /dev/null +++ b/skills/diagnose-apple-entitlements/references/artifact-and-nested-code-inspection.md @@ -0,0 +1,22 @@ +# Artifact And Nested-Code Inspection + +## Preserve identity + +Hash or otherwise identify the exact app/package, record its source/export configuration and transformations, and inspect without re-signing. Treat Debug, Release, archive, export, copied, patched, and re-signed variants as different artifacts. + +## Inspect every responsible executable + +Enumerate the main executable, app extensions, XPC services, login/background helpers, privileged helpers, command-line tools/daemons, frameworks with executable code, and embedded provisioning profiles. Record bundle ID, Team ID, designated requirement, signer/flags, and entitlements for each relevant target. + +```bash +codesign --display --verbose=4 /path/to/App.app +codesign --display --entitlements :- /path/to/App.app +codesign --verify --deep --strict --verbose=2 /path/to/App.app +security cms -D -i /path/to/embedded.provisionprofile +``` + +Locate nested code explicitly and run the relevant inspection against each executable. `codesign --deep` verification is not a substitute for comparing nested entitlements and responsible-code identity. + +## Compare + +Compare source entitlements, profile entitlements, final signed entitlements, identifier/team/environment values, sandbox/Hardened Runtime state, and runtime process identity. Do not expose certificate/profile secrets in reports. Rebuild/export from corrected source; do not hand-edit an artifact and present the result as a project fix. diff --git a/skills/diagnose-apple-entitlements/references/customization-flow.md b/skills/diagnose-apple-entitlements/references/customization-flow.md new file mode 100644 index 00000000..11717804 --- /dev/null +++ b/skills/diagnose-apple-entitlements/references/customization-flow.md @@ -0,0 +1,5 @@ +# Diagnose Apple Entitlements Customization Contract + +The first version defines no runtime-enforced knobs. `scripts/customization_config.py` preserves the shared Apple Dev Skills customization contract; the five-state comparison and final-artifact validation remain mandatory. + +Inspect settings with `scripts/customization_config.py effective`, persist a documented change with `apply --input `, and verify the effective result afterward. diff --git a/skills/diagnose-apple-entitlements/references/customization.template.yaml b/skills/diagnose-apple-entitlements/references/customization.template.yaml new file mode 100644 index 00000000..cddd82d1 --- /dev/null +++ b/skills/diagnose-apple-entitlements/references/customization.template.yaml @@ -0,0 +1,3 @@ +schemaVersion: 1 +isCustomized: false +settings: {} diff --git a/skills/diagnose-apple-entitlements/references/five-state-entitlement-comparison.md b/skills/diagnose-apple-entitlements/references/five-state-entitlement-comparison.md new file mode 100644 index 00000000..d573833a --- /dev/null +++ b/skills/diagnose-apple-entitlements/references/five-state-entitlement-comparison.md @@ -0,0 +1,13 @@ +# Five-State Entitlement Comparison + +| State | Capture | Proves | Does not prove | +| --- | --- | --- | --- | +| 1. Desired behavior | Operation/target, platform and OS, distribution, current Apple requirement, exact error | The capability being investigated | Project or account configuration | +| 2. Tracked source | Xcode capability, `.entitlements`, Info.plist, build settings, target membership, generated-project source, helper/extension config | What the repository intends for a configuration | Profile authorization or final signature | +| 3. Account authorization | Team/App ID capability, approval, certificate, profile entitlements, environment/device scope | What Apple/account/profile authorizes for that identity | What the build actually signed or runtime allows | +| 4. Signed result | Main and nested executable entitlements, code requirements, signer/Team ID, embedded profile, Hardened Runtime/signing flags | What the exact artifact declares | User consent, service authorization, or successful access | +| 5. Runtime result | Responsible process, sandbox/TCC/service/system policy, exact error/log, operation result | What this artifact did in this environment | Portable behavior on another build/artifact | + +Compare exact values as well as key presence. Record Debug/Release/archive/export, development/distribution/ad hoc signing, original/re-signed state, and every nested target independently. Classify a mismatch at the first state where expected and observed evidence diverge. + +Keep usage descriptions separate: they explain a privacy request but are not entitlements. Keep Xcode capabilities separate: they may coordinate project and account configuration but are not themselves the final signed value. diff --git a/skills/diagnose-apple-entitlements/references/restricted-and-private-entitlements.md b/skills/diagnose-apple-entitlements/references/restricted-and-private-entitlements.md new file mode 100644 index 00000000..2f4d55bb --- /dev/null +++ b/skills/diagnose-apple-entitlements/references/restricted-and-private-entitlements.md @@ -0,0 +1,20 @@ +# Restricted And Private Entitlements + +## Classification + +- **Public**: documented for third-party use with published value/platform constraints. +- **Restricted**: documented but requires an Apple approval, request, agreement, or account authorization beyond adding a key. +- **Private or undocumented**: observed in Apple/system artifacts or private interfaces without a supported third-party contract. +- **Development-only**: enables debugger/development behavior and is inappropriate or absent in distribution. +- **Environment-specific**: value binds development/production service state, team, container, or another environment. +- **Exception**: narrowly relaxes App Sandbox or Hardened Runtime behavior; never a general bypass. + +## Decision rules + +Verify the exact key, value type, platform/OS availability, required capability/approval, and provisioning support through current Apple documentation and the selected SDK. Do not infer availability from a symbol/string in another binary or from build success. + +For restricted entitlements, route the account request to `apple-developer-provisioning-workflow` and preserve the response/profile evidence. Adding an unapproved key does not create authorization. + +For private or undocumented entitlements, do not recommend them for an ordinary third-party product. Route legitimate exact-build research to `research-macos-security-control`, and distinguish Apple/platform-binary context from third-party feasibility. + +App Sandbox exceptions and Hardened Runtime exceptions govern different systems. Name the specific restriction being relaxed, use the narrowest documented exception, inspect the final signature, and validate the runtime operation. diff --git a/skills/diagnose-apple-entitlements/references/routing-and-validation.md b/skills/diagnose-apple-entitlements/references/routing-and-validation.md new file mode 100644 index 00000000..5c4fd307 --- /dev/null +++ b/skills/diagnose-apple-entitlements/references/routing-and-validation.md @@ -0,0 +1,14 @@ +# Routing And Validation + +| First mismatch | Owner | Required validation | +| --- | --- | --- | +| Desired behavior is unsupported or documentation differs | Product/design plus `explore-apple-swift-docs` | Current documented alternative or explicit unsupported state | +| Tracked capability, entitlement, Info.plist, target, or build setting | Xcode project/build workflow | Rebuilt intended configuration and inspected artifact | +| App ID, restricted approval, certificate, or profile | `apple-developer-provisioning-workflow` | Regenerated/refreshed profile plus rebuilt artifact | +| Signed main/nested code differs from source/profile | Xcode build/export or `macos-distribution-workflow` | Exact nested signatures and entitlements after clean export | +| Privacy consent or managed policy | `macos-privacy-permissions-workflow` | Public status/decision plus actual operation | +| Sandbox file authorization | `macos-sandbox-file-access-workflow` | Selection/bookmark/process-boundary result | +| Gatekeeper, notarization, Hardened Runtime, library validation | `macos-distribution-workflow` | Exported artifact assessment/runtime result | +| Private enforcement, platform-binary, SIP/Data Vault, unexplained exact-build policy | Reverse Engineering | Exact-build technical note with observation/inference split | + +After correction, repeat all five states. A local build passing is not customer/distribution proof; an entitlement appearing in a signature is not runtime proof. Report the narrow validated environment and any other distribution, device, OS, helper, or account state that remains untested. diff --git a/skills/diagnose-apple-entitlements/references/snippets/apple-xcode-project-core.md b/skills/diagnose-apple-entitlements/references/snippets/apple-xcode-project-core.md new file mode 100644 index 00000000..f161db8e --- /dev/null +++ b/skills/diagnose-apple-entitlements/references/snippets/apple-xcode-project-core.md @@ -0,0 +1,142 @@ +# Apple Xcode Project Core AGENTS Snippet + +Use this snippet in repository `AGENTS.md` files when you want baseline standards for an existing native Apple app project managed through Xcode. + +## General Swift Baseline + +- For any Swift, Apple-framework, Apple-platform, SwiftUI, SwiftData, Observation, AppKit, UIKit, Foundation-on-Apple, or Xcode-related task, read the relevant Apple documentation first before planning, proposing, or making changes. +- For Apple, Swift, and Xcode documentation, use Xcode MCP `DocumentationSearch` first. Then use the Dash.app MCP when its installed docsets cover the question. Use Dash localhost HTTP only when the Dash.app MCP is unavailable or incomplete; use checked-out source, generated DocC, GitHub/source repositories, release notes, and readable online documentation only after those local MCP paths. Generic no-JS web search/open results, snippets, metadata shells, or bare Apple Developer URLs are not enough evidence that Apple docs were read. +- Before proposing an architecture or implementation, state the documented API behavior, lifecycle rule, or workflow requirement being relied on. +- Do not rely on memory, habit, or analogy as the primary source when Apple documentation exists. +- If Apple documentation and the current code disagree, stop and report the conflict before continuing. +- If no relevant Apple documentation can be found, say that explicitly before proceeding. +- Prefer the simplest correct Swift that is easiest to read, reason about, and maintain. +- Treat idiomatic Swift, Cocoa conventions, and modern Swift features as tools in service of readability, not as goals by themselves. +- Do not add ceremony, abstraction, or boilerplate just to make code look more architectural, more generic, or more "Swifty". +- Strongly prefer synthesized, implicit, and framework-provided behavior over custom code. +- Prefer synthesized conformances (`Codable`, `Equatable`, `Hashable`, etc.) whenever they satisfy the actual requirements. +- Prefer memberwise and otherwise synthesized initializers, default property values, and framework defaults over handwritten setup code. +- Do not add `CodingKeys`, manual `Codable` methods, custom initializers, wrappers, helper types, protocols, coordinators, or extra layers unless they are required by a concrete constraint or they make the final code clearly easier to understand. +- Prefer applicable existing framework or platform error types before inventing custom error wrappers or error hierarchies. +- Prefer direct, simple error flows and small focused error enums only when they materially improve understanding. +- Prefer stable, source-of-truth naming across layers when the data and meaning have not changed. +- Treat naming consistency as a reliability feature: if the same data still serves the same purpose, keep the same name. +- Do not rename fields just to match local style conventions when the external schema is already clear and stable. +- Do not use automatic case-conversion strategies such as `.convertFromSnakeCase` or `.convertToSnakeCase` unless the project explicitly wants that behavior and it clearly improves readability overall. +- When an API, cloud service, or wire format already provides clear names, preserve those names directly in Swift models and nearby code unless the meaning actually changes or a concrete collision must be resolved. +- Preserve raw wire and persistence shapes by default; do not add DTO, domain, or view-model conversion layers unless meaning actually changes or a concrete boundary requires it. +- Treat redundant wrappers, rename-and-copy layers, and duplicated logic as anti-patterns by default. +- This guidance is optimized for an advanced Swift reader and may prefer dense but readable modern Swift over beginner-style explicitness. +- Prefer explicit names that are consistent, unambiguous, and easy to scan at the call site. +- For public Swift APIs, treat streamlined, compact, ergonomic call sites as the only acceptable default; do not grow method families, overload sets, or loosely typed entry points when one clear typed API can express the operation. +- Prefer optional parameters with explicit default values over additional methods or overloads whenever the difference is optional behavior on the same operation. +- When a public function, initializer, or method reaches four or more arguments or parameters, strongly prefer a named typed `struct` request, options, or configuration value so call sites stay readable and future additions do not multiply overloads. +- Prefer enums, enum cases with associated values, and narrow typed values over strings, booleans, sentinel values, or parallel parameters whenever the domain has a closed or meaningful set of choices. +- Prefer compact syntax when it improves local reasoning, including shorthand syntax, ternary expressions, trailing closures, enums, `switch`, `map`, `filter`, `forEach`, async iteration, `AsyncSequence`, `AsyncStream`, and `AsyncAlgorithms`. +- Prefer explicit default values at initialization when they reduce optional-handling clutter and keep the code easier to follow. +- When lines, chains, or expressions get long, prefer chopping them down into a clean vertical, top-down structure with straight visual flow. +- Do not force value types by default, protocols at seams, actors by default, or other pattern slogans when a plainer concrete implementation is easier to reason about. +- Keep code compliant with Swift 6 language mode. +- Keep strict concurrency checking enabled. +- Prefer modern structured concurrency (`async`/`await`, task groups, actors) over legacy async patterns when it keeps the flow clearer and more direct. +- Make async code cancellation-aware and keep actor or task boundaries explicit instead of hiding them behind detached tasks or queue wrappers. +- Prefer clear `Sendable` boundaries for values that cross task or actor isolation, and keep unchecked sendability exceptional and justified locally. +- Prefer Swift Testing (`import Testing`) as the default test framework, and use XCTest only when a dependency or platform constraint requires it. +- Prefer Swift Testing for unit-style and package-style test surfaces in modern Xcode projects, including suites, tags, parameterized tests, and direct async tests. +- Use XCTest when the platform surface, dependency graph, or Apple tooling still expects it, and keep XCTest and Swift Testing responsibilities clearly separated when both coexist. +- Use XCUITest for UI automation, and prefer explicit element wait APIs such as `waitForExistence(timeout:)`, `waitForNonExistence(timeout:)`, and related state waits over fixed sleeps. +- Keep `.xctestplan` files versioned when test configurations, diagnostics, sanitizers, locale coverage, or selective plan execution matter, and inspect or run them explicitly with `xcodebuild -showTestPlans` and `xcodebuild -testPlan ...`. +- Prefer normal Xcode and XCTest parallel execution for ordinary Swift Testing, XCTest, and XCUITest runs when the project, scheme, destination, and test plan support it. Do not serialize regular tests just because they use Swift, XCTest, async tests, UI automation, or `.xctestplan` matrices. +- Treat tests that load large local AI or ML models, especially models over 500 million parameters, as heavy system-resource tests. Run those tests sequentially, one at a time. +- Prefer first-party and top-tier Swift ecosystem packages from Apple, `swiftlang`, the Swift Server Work Group, and similarly trusted core Swift projects when they simplify the code and make it easier to reason about. +- Commonly approved examples include `swift-configuration` and `swift-async-algorithms` when they reduce bespoke code and improve readability. +- For Apple app projects, prefer Apple-native logging facilities first and allow Swift Logging where it makes the project API clearer. +- Prefer Swift OpenTelemetry for telemetry and instrumentation when telemetry is needed, and prefer existing ecosystem integrations over bespoke wrappers. +- Prefer a checked-in repo-root `.swiftformat` file as the default Swift formatting source of truth, and prefer a pre-commit hook that formats staged Swift sources and then verifies them with `swiftformat --lint` before commit. +- Treat SwiftLint as an optional complementary signal layer for clarity, safety, and maintainability after SwiftFormat owns formatting shape. +- Keep automation and CI commands deterministic, non-interactive, and explicit about toolchain, platform, and configuration assumptions. + +## SwiftUI and State Architecture + +- Treat SwiftUI as declarative component UI, closer to React, F# Fabulous, and Elm than to imperative AppKit or UIKit code. Keep views self-contained, reactive, flexible, reusable, and easy to scan from top to bottom. +- Give each independently reusable view a declarative interface of plain values, narrow bindings, and action closures. Do not inject external ViewModels, stores, coordinators, managers, services, or other collaborating objects from one reusable view into another. +- Choose and record one explicit three-letter uppercase prefix for every app or package. Prefix project-owned Swift files and primary declarations; exempt only `Package.swift`, externally generated Swift, and vendored third-party Swift. +- Never use `+` in project-owned Swift filenames. Concatenate the owner and concern so Xcode navigation, rename, and refactoring keep one consistent grammar. +- Name views `GEAWhateverView.swift` and extracted modifiers `GEAWhateverViewModifier.swift`. Do not introduce ViewModel files as a SwiftUI default. +- Give independently editable or previewable view components their own files. Small private computed view properties or helper views may remain while they do not clutter focused editing or previews. +- Prefix extracted child components with their complete composition owner, such as `GEASettingsSheetToggleCard.swift`. +- Extract a custom `ViewModifier` after more than eight chained modifiers, or earlier when a coherent chain is reusable or obscures the view body. +- Prefer straight, top-down data flow with state owned at the narrowest view, scene, or app boundary that matches the behavior. +- Prefer `@State`, derived values, bindings, and small private helpers for component-local presentation state. When a component genuinely needs an observable state type, create and own it locally with `@State`; do not pass it to a separately reusable view. +- Do not build monolithic views, monolithic controllers, or broad shared mutable state when a smaller component boundary would be clearer. +- Keep updates to view-driving state minimal and localized. +- Prefer durable identity for types that drive SwiftUI state and view updates. +- Treat `App` as the application entry and scene composition boundary, `Scene` as the container for scene-specific lifecycle and environment, and `View` as the component rendering layer. +- Every native app target must have exactly one app lifecycle entry point: one `@main` app type, one `main.swift`, or the platform-equivalent single launch entry. Do not add alternate app entry points, second `@main` types, duplicate `main.swift` files, target-specific app entry files, or parallel app structs for variants. When launch behavior must differ by platform, configuration, or feature flag, keep the single entry point and use Swift conditional compilation or ordinary runtime conditionals inside that boundary. +- Use app-level lifecycle concerns at the `App` boundary, scene lifecycle concerns at the `Scene` boundary, and view-local active or presentation behavior inside views. +- Use `@Binding` to pass a focused writable piece of parent-owned state into a child view. +- Use `@Bindable` when working with an observable model that should project bindings to its mutable properties in a view. +- Use the dedicated SwiftData workflow for persistence architecture and its direct SwiftUI integration path. +- Prefer existing SwiftUI environment values and actions before inventing an equivalent router or service. Use environment values for shared context that truly belongs to the surrounding hierarchy, not as a dumping ground for unrelated dependencies. +- Model app capabilities as direct, concrete feature services. A service provides one capability or a cohesive group of related operations directly to the app; it talks directly to the framework, persistence, network, or system boundary that capability needs instead of forwarding through an app-service wrapper, repository stack, or manager chain. +- Create a feature service at the narrowest app or scene boundary that owns its lifecycle. Put a service into the SwiftUI environment only when independent descendants need to invoke it or observe its state directly. Keep a service private to its feature root when that is the only consumer. +- A service may be `@Observable` when the UI must observe its feature state. Otherwise prefer direct values, async operations, explicit errors, and narrow action closures. Reusable leaf views still receive only values, bindings, and action closures; never pass a service, repository, coordinator, manager, ViewModel, store, or other collaborator into their public interface. +- Keep services concrete by default. Introduce a protocol only for a demonstrated alternate implementation or boundary that cannot otherwise be tested; do not create protocol, adapter, or wrapper layers merely because a service exists. +- Add custom environment values or actions when a capability is dynamic across the hierarchy or shared by many independent components. Keep actions local to the owning component when only that component and its private child views use them. +- Use preference keys only to publish descendant-derived information upward to an ancestor, never as a general state bus. +- Prefer Swift's synthesized memberwise initializer for view properties. Do not write an explicit initializer unless it has real behavior beyond assigning those properties. +- Prefer key-path-based APIs, predicates, and sort descriptors when they keep data access direct and readable. +- Extract repeated chains of view modifiers into custom view modifiers early when that reduces clutter and clearly matches a view or family of views. + +## Xcode Workspace and Project Baseline + +- Treat the `.xcworkspace` or `.xcodeproj` as the source of truth for Apple platform app integration, schemes, build settings, destinations, and target membership. +- Prefer edits through Xcode-aware project structure and keep project file changes intentional and reviewed closely. +- Use the standard top-level Xcode app repository layout when creating or normalizing native app repos: `Sources/`, `Tests/`, `Shared/`, `Extensions/`, `Configurations/`, `Scripts/`, and `Packages/`. +- `Sources/` owns the main app target implementation and app-owned resources/support files. `Tests/` owns all test targets. `Shared/` owns reusable source intended to be compiled into the app and extension targets. `Extensions/` owns extension target roots, one folder per extension. `Configurations/` owns `.xcconfig` layers. `Scripts/` owns project-local automation and build helper scripts. `Packages/` owns local Swift packages only when a real package boundary is justified. +- Keep those top-level roots stable. Do not invent parallel names such as `AppSources`, `TestSources`, `Config`, `BuildScripts`, or `LocalPackages` for ordinary Xcode app repos unless the existing repo already has a deliberate, documented convention. +- Inside `Sources/`, use this strict app structure by default: `Views/`, `Models/`, and `Services/`. Do not create a root `Controllers/` directory. +- `Sources/Views/` owns SwiftUI views and UIKit/AppKit view surfaces. Use `Sources/Views/Shared`, `Sources/Views/macOS`, and `Sources/Views/iOS` so shared, macOS-specific, and iOS/iPadOS-specific UI have clear homes. +- Use bare prefixed names such as `GEAWhatever.swift` for runtime/domain values. Reserve `GEAWhateverModel.swift` for persistence, and use `GEAWhateverRecord.swift` or `GEAWhateverDTO.swift` only for genuinely additional representations. +- `Sources/Models/` owns Core Data and SwiftData persistence models plus additional record or transfer representations. +- `Sources/Services/` owns direct concrete feature and boundary services. Use `Consumed/` for external capabilities the app calls, `Internal/` for app-owned feature services, and `Provided/` for services the app exposes to extensions, helpers, plugins, integrations, or other clients. These directories describe ownership and direction; they do not justify wrapper layers or an app-wide service container. +- Name a service for its capability, such as `GEADownloadService.swift` or `GEAImportService.swift`. Do not create `GEAAppService.swift` as an umbrella service by default; `GEAApp.swift` remains the lifecycle-entry special case. +- Use `xcodebuild` for Apple platform integration validation, including scheme, destination or SDK, and configuration-specific build or test runs. +- Keep `xcodebuild` invocations reproducible in automation by passing explicit schemes, destinations or SDKs, and configurations when relevant. +- For Codex GUI worktree-first Xcode repos, use a portable `.codex/environments/*.toml` local environment file when the repo wants shared app setup or action buttons. Start from `apple-dev-skills/templates/codex-local-environments/xcode-project.toml`, keep paths repo-relative, and prefer `-derivedDataPath ./DerivedData` or another ignored repo-local build directory instead of user-global DerivedData. +- When scripts or terminal workflows add files on disk, verify that Xcode project membership, target membership, build-phase membership, and resource-bundle inclusion all match the intended result; files appearing in the directory tree alone are not enough. +- Direct filesystem edits outside `.pbxproj` are generally safe when Xcode is closed or when the current project is not open in Xcode, but still verify that the Xcode project picks up the intended files and memberships afterward. +- Prefer Debug builds for everyday edit-build-test loops, but validate Release builds explicitly when optimization, packaging, launch behavior, watchdog timing, or deployment realism matters. +- Treat tagged releases as a signal to validate both the normal Debug path and a Release artifact path, and when shipping apps or deliverables test the Release behavior without relying on an attached debugger. +- Prefer direct filesystem edits in Xcode-managed scope only when the workflow already accounts for project-file and scheme integrity. +- Never edit `.pbxproj` files directly. If a project-file change is needed and no safe project-aware tool is available, stop and ask for an Xcode-mediated project change instead. When `.pbxproj` is tracked and Xcode, XcodeGen, or another project-aware workflow legitimately changes it, treat that diff as critical project state: review it, stage it, and commit it with the branch before any push, merge, release, or cleanup. + +## XcodeGen and Build Configuration Defaults + +- For new Xcode app, framework, and workspace repositories, prefer an XcodeGen-backed project by default unless the user explicitly asks for a hand-managed Xcode project or the repository has a concrete reason to avoid a generator dependency. +- If the repo contains `project.yml`, `project.yaml`, or clearly named included XcodeGen spec files, treat the XcodeGen spec set as the source of truth for generated project structure. +- For XcodeGen-backed repos, make target membership, resource membership, schemes, Swift package declarations, test-plan references, project references, build configurations, configuration-file wiring, generation options, and project-level settings in the XcodeGen specs instead of editing the generated `.pbxproj`. +- Before running `xcodegen generate`, inspect the current git diff for generated `.xcodeproj` or `.pbxproj` changes. Treat existing project-file diffs as intentional user or Xcode GUI changes by default, not disposable generator drift. +- When Xcode GUI changes added build settings, signing settings, capabilities, `Info.plist` build setting overrides, file membership, scheme changes, or entitlement wiring to `.pbxproj`, preserve the user intent by moving each intentional value to the owning tracked source first: XcodeGen spec for structure, `.xcconfig` for build settings, `.entitlements` for entitlement keys, `Info.plist` for plist keys, `.xcscheme` or scheme spec for scheme behavior, and `.xctestplan` for test-plan content. +- Only regenerate after that promotion is complete, then review the generated project diff to confirm XcodeGen preserved the intended behavior instead of deleting it. If the owning tracked file is ambiguous, stop and ask before regenerating. +- For new XcodeGen-backed app scaffolds, start from the maintained `apple-dev-skills/templates/xcodegen/` templates when available instead of inventing a fresh project-spec shape from memory. +- Keep `minimumXcodeGenVersion` on a recent validated release for new scaffolds. Prefer updating the template and validation together when the repo intentionally raises the baseline. +- For Xcode 16 or newer project formats, prefer XcodeGen `syncedFolder` roots at the broad top-level directory boundary so file creation, deletion, and organization stay synchronized between Xcode and the filesystem without hand-listing every source file in YAML. +- Do not fragment ordinary XcodeGen source roots by subdirectory. A standard app target gets one `Sources` source entry that includes all app source, resource, support, generated plist, entitlement, and nested feature folders, plus one `Shared` source entry when shared app/extension code exists. A standard test target gets one `Tests` source entry that includes all test subdirectories. Extension targets use one `Extensions/` source entry per extension target. If a project has another separate top-level logical root, use one top-level entry for that root, not one entry per child folder. +- Never split `Sources/App`, `Sources/Resources`, `Sources/Support`, feature folders, or `Tests/Tests` into separate XcodeGen source entries unless a specific non-ordinary file or folder truly needs custom compiler flags, build-phase routing, destination filters, or target membership that cannot be represented from the broad root. +- If `syncedFolder` behaves poorly for a repo, fall back to the same broad top-level recursive paths such as `Sources`, `Tests`, or `Resources` with explicit `includes` and `excludes`; do not fall back to subdirectory-level fragmentation or one YAML entry per ordinary source file. +- Keep XcodeGen specs readable as project structure, not as a dumping ground for every build setting. Use `configs`, `configFiles`, `targets`, `schemes`, `packages`, `projectReferences`, `targetTemplates`, and `schemeTemplates` deliberately so future edits have an obvious owner. +- Prefer explicit top-level schemes for app scaffolds once scheme behavior matters. Put build, run, test, profile, analyze, archive, environment variables, command-line arguments, and test-plan references in the scheme spec rather than relying on hidden generated defaults. +- Prefer external `.xcconfig` files as the default home for nontrivial build settings. Keep build settings in XcodeGen inline settings only when they are small, local, and clearer there. +- Use `.xcconfig` files for settings that vary by Debug, Release, CI, local development, signing, bundle identity, compiler flags, Swift settings, deployment variants, or environment-specific behavior. +- Keep configuration layering explicit. Prefer a small shared base config, target-level configs for app/test/extension identity, then per-configuration configs that include the narrower target config and override only what changes. +- In XcodeGen specs, wire build configurations to their matching `.xcconfig` files instead of duplicating the same settings across generated project objects. +- Prefer checked-in external `.entitlements` files for app, extension, and capability-bearing targets, with `CODE_SIGN_ENTITLEMENTS` declared in the owning target's `.xcconfig`. Let Xcode capabilities update the entitlement plist when possible, then review and commit the entitlement diff; keep XcodeGen responsible for wiring the file, not regenerating its contents from inline YAML. +- Do not assume Xcode's Build Settings UI writes edited values back into `.xcconfig` files. When a build setting should remain tracked in `.xcconfig`, inspect the generated project diff after GUI changes and move intentional build-setting overrides from `.pbxproj` back into the owning `.xcconfig` before regenerating. +- Keep secrets, personal team IDs, local machine paths, provisioning profiles, API tokens, and private signing material out of committed `.xcconfig` files. Use build settings only for non-secret configuration values, safe placeholders, references to externally supplied values, or local developer placeholders that are safe to commit. +- Before changing generated project structure, inspect the root spec plus any `include` entries so the edit lands in the owning spec rather than duplicating settings in the wrong file. Remember that included specs merge into the root spec, and local overrides may intentionally replace arrays or maps. +- After changing XcodeGen specs, `.xcconfig` files, or entitlement-file wiring, run `xcodegen generate` from the spec root, or `xcodegen generate --spec ` when the project uses a non-default spec path. +- If the spec uses environment variables or generation hooks, preserve and document the required environment before regenerating so CI and other contributors can reproduce the project. +- Review the spec diff, `.xcconfig` diff, and generated `.xcodeproj` diff after regeneration. Generated `.pbxproj` changes are acceptable output when they come from XcodeGen, but they should still be reviewed for unintended target, scheme, signing, package, build-setting, or file-membership churn. +- Validate regenerated projects with explicit `xcodebuild` commands for the affected scheme, destination or SDK, and configuration. +- For existing hand-managed Xcode projects, do not migrate to XcodeGen or externalize build settings into `.xcconfig` files unless the user explicitly asks for that migration. When they do, treat it as a project-structure migration with before/after validation. diff --git a/skills/diagnose-apple-entitlements/scripts/customization_config.py b/skills/diagnose-apple-entitlements/scripts/customization_config.py new file mode 100755 index 00000000..158abb46 --- /dev/null +++ b/skills/diagnose-apple-entitlements/scripts/customization_config.py @@ -0,0 +1,104 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.9" +# dependencies = ["PyYAML>=6.0.2,<7"] +# /// +"""Load and persist entitlement-diagnosis customization state.""" + +from __future__ import annotations + +import argparse +import os +import re +import sys +from pathlib import Path + +import yaml + +SKILL_NAME = "diagnose-apple-entitlements" +ROOT = "~/.config/gaelic-ghost/apple-dev-skills" +KEYS = {"schemaVersion", "isCustomized", "settings"} + + +def fail(message: str) -> None: + print(f"ERROR: {message}", file=sys.stderr) + raise SystemExit(1) + + +def read(path: Path, required: bool = False) -> dict: + if not path.exists(): + if required: + fail(f"Missing YAML file: {path}") + return {} + try: + value = yaml.safe_load(path.read_text(encoding="utf-8")) or {} + except yaml.YAMLError as error: + fail(f"Invalid YAML in {path}: {error}") + if not isinstance(value, dict): + fail(f"Top-level YAML document must be a mapping in {path}") + return value + + +def validate(value: dict, partial: bool = False) -> None: + if set(value) - KEYS: + fail(f"Unknown top-level keys: {', '.join(sorted(set(value) - KEYS))}") + if not partial and set(value) != KEYS: + fail("State must define schemaVersion, isCustomized, and settings") + if "schemaVersion" in value and value["schemaVersion"] != 1: + fail("schemaVersion must be 1") + if "isCustomized" in value and not isinstance(value["isCustomized"], bool): + fail("isCustomized must be boolean") + if "settings" in value: + if not isinstance(value["settings"], dict): + fail("settings must be a mapping") + for key, item in value["settings"].items(): + if not re.fullmatch(r"[A-Za-z0-9_]+", str(key)): + fail(f"Invalid settings key: {key}") + if isinstance(item, (dict, list)): + fail(f"settings values must be scalar: {key}") + + +def destination() -> Path: + root = Path(os.environ.get("APPLE_DEV_SKILLS_CONFIG_HOME", ROOT)).expanduser() + return root / SKILL_NAME / "customization.yaml" + + +def current() -> dict: + template = read(Path(__file__).resolve().parents[1] / "references/customization.template.yaml", True) + saved = read(destination()) + validate(template) + if saved: + validate(saved) + return {"schemaVersion": 1, "isCustomized": saved.get("isCustomized", False), "settings": {**template["settings"], **saved.get("settings", {})}} + + +def main() -> None: + parser = argparse.ArgumentParser(description="Manage entitlement-diagnosis customization") + command = parser.add_subparsers(dest="command", required=True) + command.add_parser("path") + command.add_parser("effective") + apply = command.add_parser("apply") + apply.add_argument("--input", required=True) + command.add_parser("reset") + args = parser.parse_args() + target = destination() + if args.command == "path": + print(target) + elif args.command == "effective": + print(yaml.safe_dump(current(), sort_keys=False), end="") + elif args.command == "reset": + if target.exists(): + target.unlink() + print(target) + else: + incoming = read(Path(args.input), True) + validate(incoming, partial=True) + updated = {"schemaVersion": 1, "isCustomized": True, "settings": {**current()["settings"], **incoming.get("settings", {})}} + validate(updated) + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(yaml.safe_dump(updated, sort_keys=False), encoding="utf-8") + print(target) + + +if __name__ == "__main__": + main() diff --git a/skills/file-provider-and-finder-sync-workflow/SKILL.md b/skills/file-provider-and-finder-sync-workflow/SKILL.md index b2284f1d..8cff5020 100644 --- a/skills/file-provider-and-finder-sync-workflow/SKILL.md +++ b/skills/file-provider-and-finder-sync-workflow/SKILL.md @@ -84,6 +84,7 @@ This skill owns that decision, File Provider synchronization mechanics, and Find ## Fallbacks and Handoffs +- Recommend `macos-sandbox-file-access-workflow` when the real requirement is local user-selected files, security-scoped bookmarks, App Groups, or persistent sandbox access rather than a File Provider domain or Finder UI. - Recommend `app-extension-architecture-workflow` for extension targets, process isolation, entitlements, App Groups, and shared containers. - Recommend `swift-openapi-client-workflow` for generated Apple client transport integration. - Recommend `xcode-build-run-workflow` for target configuration, capabilities, signing, embedding, install, and run work. diff --git a/skills/harden-macos/SKILL.md b/skills/harden-macos/SKILL.md index 148fd7c2..8f785aca 100644 --- a/skills/harden-macos/SKILL.md +++ b/skills/harden-macos/SKILL.md @@ -19,6 +19,7 @@ Read [references/macos-hardening-review.md](references/macos-hardening-review.md - Verify OS, rapid/security data updates, browsers, extensions, apps, and package managers from authoritative channels. 3. Preserve platform protections. - Verify Gatekeeper/XProtect automatic protection, SIP, TCC/privacy access, code-signing expectations, and sandbox/container use where applicable. + - Keep this defensive posture review separate from developer prompt/request implementation; route ordinary app permission design to `macos-privacy-permissions-workflow`. 4. Protect data and recovery. - Review FileVault/recovery ownership, screen lock, backup availability and restore testing, account separation, and secure disposal/export practices. 5. Reduce exposed services and persistence. diff --git a/skills/inspect-macos-runtime-activity/SKILL.md b/skills/inspect-macos-runtime-activity/SKILL.md index 16f3134c..b5741eb7 100644 --- a/skills/inspect-macos-runtime-activity/SKILL.md +++ b/skills/inspect-macos-runtime-activity/SKILL.md @@ -24,6 +24,7 @@ Read [references/macos-runtime-evidence.md](references/macos-runtime-evidence.md 5. Inspect focused logs/events. - Query relevant unified logs and existing Endpoint Security/XProtect/Gatekeeper evidence for the narrow time window. - Record Full Disk Access, root, Endpoint Security entitlement, or other permissions required and what absence hides. + - Treat missing collection permission or unavailable event types as a telemetry gap, not evidence that the behavior did not occur. Route app-facing permission implementation to `macos-privacy-permissions-workflow` and exact private-control interpretation to `research-macos-security-control`. 6. Build a timeline. - Separate user action, launch, child processes, file changes, prompts, network, persistence, detection, and termination. 7. Assess behavior and gaps. diff --git a/skills/inspect-macos-runtime-activity/references/macos-runtime-evidence.md b/skills/inspect-macos-runtime-activity/references/macos-runtime-evidence.md index be9909ea..6f0fff83 100644 --- a/skills/inspect-macos-runtime-activity/references/macos-runtime-evidence.md +++ b/skills/inspect-macos-runtime-activity/references/macos-runtime-evidence.md @@ -10,3 +10,5 @@ | TCC/system settings | declared or granted privacy access | grant presence does not prove use | Record failed commands and missing permissions. Do not silently substitute missing telemetry with assumptions. + +Record the exact collecting executable, permission class, approval state, event subscription, time window, filter, retention, and privacy redaction. If collection needs a supported privacy decision, hand implementation to `apple-dev-skills:macos-privacy-permissions-workflow`; do not treat granting a broad terminal or agent host as equivalent to authorizing a narrow collector. diff --git a/skills/macos-privacy-permissions-workflow/SKILL.md b/skills/macos-privacy-permissions-workflow/SKILL.md new file mode 100644 index 00000000..c54cd9ec --- /dev/null +++ b/skills/macos-privacy-permissions-workflow/SKILL.md @@ -0,0 +1,74 @@ +--- +name: macos-privacy-permissions-workflow +description: Diagnose macOS privacy permissions from the operation and responsible executable. Use for Accessibility, Automation, Developer Tools, recording or input, protected data, Full Disk Access, PPPC, prompts, Settings, resets, and helpers. +--- + +# macOS Privacy Permissions Workflow + +## Purpose + +Identify the protected operation, responsible executable, and current public authorization contract before changing code or asking the person to change Privacy & Security settings. Keep project declarations, user consent, managed policy, and runtime success as separate evidence. + +## When To Use + +- Use for macOS privacy authorization failures, permission prompts, Settings entries, `tccutil reset`, PPPC policy, and responsible-code attribution. +- Use for Accessibility, Automation, Developer Tools, screen/system-audio recording, Input Monitoring, camera, microphone, personal data, Files and Folders, Full Disk Access, App Management, and other current macOS privacy classes. +- Do not use private TCC APIs or database details as an application implementation contract. + +## Single-Path Workflow + +1. Record the exact attempted operation, target resource or process, timestamp, user/session, error domain/code/message, and whether the evidence came from the host, a guest, or a physical Mac. +2. Resolve the responsible code: executable path, bundle identifier, Team ID, designated requirement, signing state, parent/launcher, helper or XPC boundary, and whether the artifact changed. Read `references/responsible-code-and-attribution.md`. +3. Apply the Apple docs gate through `explore-apple-swift-docs`. Record the host macOS version/build and selected SDK/Xcode, then verify the current framework API and settings name. Do not promote an internal service string to a public API. +4. Select the class in `references/permission-class-matrix.md`. Inspect the relevant usage description, entitlement/capability, sandbox state, helper identity, and final signed artifact without treating any declaration as consent. +5. Preflight or read status using the class's documented public API when one exists. Preserve `.notDetermined`, restricted or managed, denied, limited, and authorized states instead of collapsing them to Boolean access. +6. Request only from the user action that needs access and only when the public API supports requesting. Explain the operation, system UI, denial behavior, later Settings path, and any relaunch/helper restart/logout requirement. +7. For Settings-managed classes such as Full Disk Access, describe the user or MDM decision and the narrow responsible executable. Never invent a self-grant API or grant a broad terminal, IDE, or agent host without explaining its broader authority. +8. Read `references/prompting-settings-reset-and-mdm.md` before resetting or managing state. Treat `tccutil reset` as test-state removal, never grant or general status inspection. +9. Reproduce the original operation after the required lifecycle transition. Record the status/preflight result, actual operation result, responsible executable, mutations and approvals, reset/rollback path, and remaining uncertainty. +10. Use the minimum fixture in `references/validation-fixtures.md`. Obtain explicit approval immediately before any visible prompt, System Settings change, logout, or live-host permission mutation. + +## Inputs + +- attempted operation, target, exact error, and expected user-visible behavior +- app/tool/helper path, bundle identity, signer, launcher, and build transformation history +- macOS build, SDK/Xcode, management state, sandbox state, usage descriptions, and signed entitlements +- current status/preflight output, Settings state, prior prompts/resets, and reproduction environment + +## Outputs + +- responsible-code identity and controlling privacy class +- public status/request contract and required project declarations +- prompt, Settings, MDM, reset, lifecycle, and denial behavior +- reproduced operation result, exact evidence, confidence, and unresolved fidelity gaps + +## Guards and Stop Conditions + +- Do not edit, replace, copy back, or directly query a live TCC database as an app workflow. +- Do not use private `TCC.framework` APIs or `kTCCService*` constants in shipping guidance. +- Do not automate System Settings clicks to defeat user choice, repeatedly prompt, or reset a denial without an explicit test reason. +- Do not confuse a usage description, entitlement, sandbox exception, profile payload, or Settings entry with user consent. +- Stop before producing visible permission UI or mutating Gale's active Mac until Gale explicitly approves that exact action. +- Stop when the responsible executable or original protected operation cannot be identified; report the missing evidence instead of guessing a permission. + +## Fallbacks and Handoffs + +- Use `macos-sandbox-file-access-workflow` when user-selected file access, bookmarks, containers, or App Groups are the actual requirement. +- Use `diagnose-apple-entitlements` when source, profile, signed entitlement, and runtime state disagree. +- Use `apple-developer-provisioning-workflow` for account-side capability and profile changes; use Xcode workflows for project edits and builds. +- Use `research-macos-security-control` for private TCC symbols, database schemas, daemon behavior, or exact-build implementation research. +- Use Cybersecurity Skills for suspicious prompts, unexplained grants, Gatekeeper/XProtect alerts, or host compromise questions. + +## Customization + +Use `references/customization-flow.md`. The workflow has no runtime knobs; permission behavior must remain tied to the recorded identity, OS build, public API, and user or managed decision. + +## References + +- `references/permission-class-matrix.md` +- `references/responsible-code-and-attribution.md` +- `references/prompting-settings-reset-and-mdm.md` +- `references/validation-fixtures.md` +- Recommend `references/snippets/apple-xcode-project-core.md` when the diagnosis leads to an Xcode project change. +- [Controlling app access to files in macOS](https://support.apple.com/guide/security/secddd1d86a6/web) +- [Privacy Preferences Policy Control payload](https://support.apple.com/guide/deployment/privacy-preferences-policy-control-payload-dep38df53c2a/web) diff --git a/skills/macos-privacy-permissions-workflow/agents/openai.yaml b/skills/macos-privacy-permissions-workflow/agents/openai.yaml new file mode 100644 index 00000000..0ad3a273 --- /dev/null +++ b/skills/macos-privacy-permissions-workflow/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "macOS Privacy Permissions" + short_description: "Diagnose macOS privacy permission behavior" + default_prompt: "Use $macos-privacy-permissions-workflow to diagnose this macOS permission failure." diff --git a/skills/macos-privacy-permissions-workflow/references/customization-flow.md b/skills/macos-privacy-permissions-workflow/references/customization-flow.md new file mode 100644 index 00000000..b0541694 --- /dev/null +++ b/skills/macos-privacy-permissions-workflow/references/customization-flow.md @@ -0,0 +1,5 @@ +# macOS Privacy Permissions Customization Contract + +The first version defines no runtime-enforced knobs. `scripts/customization_config.py` preserves the shared Apple Dev Skills customization contract; permission conclusions must remain derived from current documentation, stable code identity, exact host state, and the recorded user or managed decision. + +Inspect settings with `scripts/customization_config.py effective`, persist a documented change with `apply --input `, and verify the effective result afterward. diff --git a/skills/macos-privacy-permissions-workflow/references/customization.template.yaml b/skills/macos-privacy-permissions-workflow/references/customization.template.yaml new file mode 100644 index 00000000..cddd82d1 --- /dev/null +++ b/skills/macos-privacy-permissions-workflow/references/customization.template.yaml @@ -0,0 +1,3 @@ +schemaVersion: 1 +isCustomized: false +settings: {} diff --git a/skills/macos-privacy-permissions-workflow/references/permission-class-matrix.md b/skills/macos-privacy-permissions-workflow/references/permission-class-matrix.md new file mode 100644 index 00000000..d61061c4 --- /dev/null +++ b/skills/macos-privacy-permissions-workflow/references/permission-class-matrix.md @@ -0,0 +1,24 @@ +# macOS Privacy Permission Class Matrix + +Verified baseline: macOS 26.5.2 build 25F84 and the selected stable Xcode SDK on 2026-07-19. Recheck the current SDK declarations and Apple documentation before implementation; System Settings names, APIs, and management results change. + +| User-facing class | Public status/preflight/request path | Declaration or capability | Interaction model | Validation focus | +| --- | --- | --- | --- | --- | +| Accessibility | `AXIsProcessTrustedWithOptions`; the prompt option can direct the user to system UI | No usage-description key; App Sandbox generally cannot provide broad AX control | Check trust for the responsible executable; user or PPPC decision | Helper/host identity, relaunch needs, actual AX operation | +| Automation | `AEDeterminePermissionToAutomateTarget` for a controller-target/event tuple | `NSAppleEventsUsageDescription`; sandboxed senders need the documented Apple Events entitlement/target allowances | Prompt is pair- and event-context-sensitive | Controller-target pair identities, not Terminal's grant | +| Developer Tools | `EPDeveloperTool.authorizationStatus` and `requestAccess()` in ExecutionPolicy | Verify current signing/sandbox constraints in the SDK; no usage-description substitute | Preserve not determined, restricted, denied, authorized; do not promise UI from `requestAccess()` | Direct tool versus Terminal, IDE, agent host, helper/XPC execution | +| Screen and system audio recording | Prefer current ScreenCaptureKit authorization behavior; CoreGraphics exposes `CGPreflightScreenCaptureAccess` and `CGRequestScreenCaptureAccess` for screen capture | Verify current usage-description keys and ScreenCaptureKit requirements in the selected SDK | Public request/preflight exists for screen capture; lifecycle behavior is version-sensitive | Screen-only versus audio selection, app identity, restart/relaunch behavior | +| Input Monitoring | Verify current public event-tap/input APIs and SDK guidance | No generic usage-description key should be invented | Usually a Settings/user or PPPC decision; an attempted protected operation may establish the entry | Event source/type, accessibility overlap, responsible executable | +| Camera and microphone | `AVCaptureDevice.authorizationStatus(for:)` and `requestAccess(for:)` | `NSCameraUsageDescription`, `NSMicrophoneUsageDescription` | Framework request from a direct user action | Device/media type, denial path, actual capture | +| Contacts | Contacts authorization APIs, including the current access level model | `NSContactsUsageDescription` and any newer access-level keys required by the SDK | Framework request; preserve limited/denied distinctions | Requested entity/access level and fetch result | +| Calendars and reminders | EventKit authorization APIs for the requested entity/access level | Current EventKit usage-description keys for events/reminders and access level | Framework request | Event versus reminders, write-only versus full access | +| Photos | `PHPhotoLibrary.authorizationStatus(for:)` and `requestAuthorization(for:)`; use PhotosUI selection when library access is unnecessary | `NSPhotoLibraryUsageDescription` and add-only key as applicable | Prefer user selection or limited access | Access level, selected assets, library operation | +| Location | Core Location authorization/status APIs | Current location usage-description keys | Framework request with service/session lifecycle | Precision, session, authorization level, operation result | +| Bluetooth, local network, media library, speech, and other framework-owned data | Use the owning framework's current authorization API | Use only keys declared by the current SDK/documentation | Framework-specific; no universal TCC request API | Service-specific status plus real operation | +| Files and Folders | No universal app self-grant API | Sandbox entitlements/bookmarks may also apply but do not replace TCC | User or PPPC decision around protected locations | Exact path class and process identity | +| Full Disk Access | No public self-grant or supported general status API | No entitlement grants ordinary third-party FDA | Explicit user or supported MDM policy decision | Narrow responsible executable, lifecycle transition, original operation | +| App Management and other current macOS-only classes | Verify current public API and deployment payload support | Do not infer a key or entitlement from an internal TCC service name | Often Settings/user or managed policy | Operation, actor/target identity, exact OS build | + +Use internal service terminology only when it is necessary to interpret a log, supported reset command, or exact-build research note. Route private constants and implementation behavior to `research-macos-security-control`. + +Sources: [Apple Platform Security](https://support.apple.com/guide/security/welcome/web), [Controlling app access to files](https://support.apple.com/guide/security/secddd1d86a6/web), [PPPC payload settings](https://support.apple.com/guide/deployment/privacy-preferences-policy-control-payload-dep38df53c2a/web), and the selected SDK headers. diff --git a/skills/macos-privacy-permissions-workflow/references/prompting-settings-reset-and-mdm.md b/skills/macos-privacy-permissions-workflow/references/prompting-settings-reset-and-mdm.md new file mode 100644 index 00000000..e00a287e --- /dev/null +++ b/skills/macos-privacy-permissions-workflow/references/prompting-settings-reset-and-mdm.md @@ -0,0 +1,24 @@ +# Prompting, Settings, Reset, And MDM + +## Request lifecycle + +1. Preflight or read the framework status without prompting when the API supports it. +2. Request from a direct user action only when the status and public contract allow a request. +3. Explain the concrete operation and target before system UI appears. +4. Preserve denied, restricted/managed, limited, and authorized as distinct states. +5. Provide a non-coercive denial path and the current Privacy & Security location when a later change is possible. +6. Apply the documented relaunch, helper restart, logout, or retry boundary, then reproduce the original operation. + +Never loop requests, hide the responsible app behind a generic host, or automate Settings to defeat consent. + +## Reset boundary + +`tccutil` is a supported reset surface, not a general grant or status tool. Before a reset, record the service/class, bundle identity, reason, current reproduction, expected next prompt, and rollback/test cleanup. Use only the syntax supported by `man tccutil` on the current OS. A reset removes a decision; it does not authorize access. + +Do not manipulate a live TCC database, copy an edited database back, or use SQL output as an app-facing support contract. Use private schemas only in an approved exact-build Reverse Engineering task. + +## MDM and PPPC + +PPPC identifies code using the documented bundle/code requirement fields and supports only the service classes and authorization values Apple documents for the current OS. A payload may allow, deny, or require user approval depending on the class; do not assume MDM can silently allow every permission. Record supervision/enrollment state, payload scope, designated requirement, authorization value, conflict/precedence evidence, and the device's applied-profile state. + +Use [Apple's PPPC payload documentation](https://support.apple.com/guide/deployment/privacy-preferences-policy-control-payload-dep38df53c2a/web) as the source of truth for current services and allowed authorization values. diff --git a/skills/macos-privacy-permissions-workflow/references/responsible-code-and-attribution.md b/skills/macos-privacy-permissions-workflow/references/responsible-code-and-attribution.md new file mode 100644 index 00000000..258b3f1c --- /dev/null +++ b/skills/macos-privacy-permissions-workflow/references/responsible-code-and-attribution.md @@ -0,0 +1,29 @@ +# Responsible Code And Attribution + +## Identity record + +Capture the executable path, bundle ID, Team ID, designated requirement, signing flags, CDHash when useful, parent/launcher, target process/resource, and transformation history. For a helper, extension, XPC service, script interpreter, or command-line tool, record both the initiating app and the process that performs the protected operation. + +Useful non-mutating inspection commands include: + +```bash +codesign --display --verbose=4 /path/to/App.app +codesign --display --entitlements :- /path/to/App.app +codesign --verify --deep --strict --verbose=2 /path/to/App.app +ps -axo pid,ppid,user,comm,args +``` + +Do not rely on `--deep` verification alone to explain nested-code identity; enumerate the actual helper/extension/XPC executables when attribution matters. + +## Attribution traps + +- A grant to Terminal, an IDE, or an agent host authorizes that signed host in the recorded context; it does not prove the built app or helper is authorized. +- Rebuilding, relocating, changing signing identity, re-signing, or launching through a different host can change the identity that TCC evaluates. +- Automation is about the controlling-target pair and requested Apple Event, not one global permission. +- A helper or XPC service can be the responsible code even when the parent app owns the UI. +- Unsigned, ad hoc, or unstable development tools make authorization evidence difficult to reproduce. Preserve the exact artifact instead of generalizing one result. +- A Settings entry is not proof that the original operation now succeeds; reproduce the operation after any required relaunch, helper restart, or logout. + +## Result statement + +Report: `artifact identity -> protected operation and target -> class/status evidence -> user or managed decision -> lifecycle transition -> reproduced result`. State whether attribution is documented, observed, or inferred. diff --git a/skills/macos-privacy-permissions-workflow/references/snippets/apple-xcode-project-core.md b/skills/macos-privacy-permissions-workflow/references/snippets/apple-xcode-project-core.md new file mode 100644 index 00000000..f161db8e --- /dev/null +++ b/skills/macos-privacy-permissions-workflow/references/snippets/apple-xcode-project-core.md @@ -0,0 +1,142 @@ +# Apple Xcode Project Core AGENTS Snippet + +Use this snippet in repository `AGENTS.md` files when you want baseline standards for an existing native Apple app project managed through Xcode. + +## General Swift Baseline + +- For any Swift, Apple-framework, Apple-platform, SwiftUI, SwiftData, Observation, AppKit, UIKit, Foundation-on-Apple, or Xcode-related task, read the relevant Apple documentation first before planning, proposing, or making changes. +- For Apple, Swift, and Xcode documentation, use Xcode MCP `DocumentationSearch` first. Then use the Dash.app MCP when its installed docsets cover the question. Use Dash localhost HTTP only when the Dash.app MCP is unavailable or incomplete; use checked-out source, generated DocC, GitHub/source repositories, release notes, and readable online documentation only after those local MCP paths. Generic no-JS web search/open results, snippets, metadata shells, or bare Apple Developer URLs are not enough evidence that Apple docs were read. +- Before proposing an architecture or implementation, state the documented API behavior, lifecycle rule, or workflow requirement being relied on. +- Do not rely on memory, habit, or analogy as the primary source when Apple documentation exists. +- If Apple documentation and the current code disagree, stop and report the conflict before continuing. +- If no relevant Apple documentation can be found, say that explicitly before proceeding. +- Prefer the simplest correct Swift that is easiest to read, reason about, and maintain. +- Treat idiomatic Swift, Cocoa conventions, and modern Swift features as tools in service of readability, not as goals by themselves. +- Do not add ceremony, abstraction, or boilerplate just to make code look more architectural, more generic, or more "Swifty". +- Strongly prefer synthesized, implicit, and framework-provided behavior over custom code. +- Prefer synthesized conformances (`Codable`, `Equatable`, `Hashable`, etc.) whenever they satisfy the actual requirements. +- Prefer memberwise and otherwise synthesized initializers, default property values, and framework defaults over handwritten setup code. +- Do not add `CodingKeys`, manual `Codable` methods, custom initializers, wrappers, helper types, protocols, coordinators, or extra layers unless they are required by a concrete constraint or they make the final code clearly easier to understand. +- Prefer applicable existing framework or platform error types before inventing custom error wrappers or error hierarchies. +- Prefer direct, simple error flows and small focused error enums only when they materially improve understanding. +- Prefer stable, source-of-truth naming across layers when the data and meaning have not changed. +- Treat naming consistency as a reliability feature: if the same data still serves the same purpose, keep the same name. +- Do not rename fields just to match local style conventions when the external schema is already clear and stable. +- Do not use automatic case-conversion strategies such as `.convertFromSnakeCase` or `.convertToSnakeCase` unless the project explicitly wants that behavior and it clearly improves readability overall. +- When an API, cloud service, or wire format already provides clear names, preserve those names directly in Swift models and nearby code unless the meaning actually changes or a concrete collision must be resolved. +- Preserve raw wire and persistence shapes by default; do not add DTO, domain, or view-model conversion layers unless meaning actually changes or a concrete boundary requires it. +- Treat redundant wrappers, rename-and-copy layers, and duplicated logic as anti-patterns by default. +- This guidance is optimized for an advanced Swift reader and may prefer dense but readable modern Swift over beginner-style explicitness. +- Prefer explicit names that are consistent, unambiguous, and easy to scan at the call site. +- For public Swift APIs, treat streamlined, compact, ergonomic call sites as the only acceptable default; do not grow method families, overload sets, or loosely typed entry points when one clear typed API can express the operation. +- Prefer optional parameters with explicit default values over additional methods or overloads whenever the difference is optional behavior on the same operation. +- When a public function, initializer, or method reaches four or more arguments or parameters, strongly prefer a named typed `struct` request, options, or configuration value so call sites stay readable and future additions do not multiply overloads. +- Prefer enums, enum cases with associated values, and narrow typed values over strings, booleans, sentinel values, or parallel parameters whenever the domain has a closed or meaningful set of choices. +- Prefer compact syntax when it improves local reasoning, including shorthand syntax, ternary expressions, trailing closures, enums, `switch`, `map`, `filter`, `forEach`, async iteration, `AsyncSequence`, `AsyncStream`, and `AsyncAlgorithms`. +- Prefer explicit default values at initialization when they reduce optional-handling clutter and keep the code easier to follow. +- When lines, chains, or expressions get long, prefer chopping them down into a clean vertical, top-down structure with straight visual flow. +- Do not force value types by default, protocols at seams, actors by default, or other pattern slogans when a plainer concrete implementation is easier to reason about. +- Keep code compliant with Swift 6 language mode. +- Keep strict concurrency checking enabled. +- Prefer modern structured concurrency (`async`/`await`, task groups, actors) over legacy async patterns when it keeps the flow clearer and more direct. +- Make async code cancellation-aware and keep actor or task boundaries explicit instead of hiding them behind detached tasks or queue wrappers. +- Prefer clear `Sendable` boundaries for values that cross task or actor isolation, and keep unchecked sendability exceptional and justified locally. +- Prefer Swift Testing (`import Testing`) as the default test framework, and use XCTest only when a dependency or platform constraint requires it. +- Prefer Swift Testing for unit-style and package-style test surfaces in modern Xcode projects, including suites, tags, parameterized tests, and direct async tests. +- Use XCTest when the platform surface, dependency graph, or Apple tooling still expects it, and keep XCTest and Swift Testing responsibilities clearly separated when both coexist. +- Use XCUITest for UI automation, and prefer explicit element wait APIs such as `waitForExistence(timeout:)`, `waitForNonExistence(timeout:)`, and related state waits over fixed sleeps. +- Keep `.xctestplan` files versioned when test configurations, diagnostics, sanitizers, locale coverage, or selective plan execution matter, and inspect or run them explicitly with `xcodebuild -showTestPlans` and `xcodebuild -testPlan ...`. +- Prefer normal Xcode and XCTest parallel execution for ordinary Swift Testing, XCTest, and XCUITest runs when the project, scheme, destination, and test plan support it. Do not serialize regular tests just because they use Swift, XCTest, async tests, UI automation, or `.xctestplan` matrices. +- Treat tests that load large local AI or ML models, especially models over 500 million parameters, as heavy system-resource tests. Run those tests sequentially, one at a time. +- Prefer first-party and top-tier Swift ecosystem packages from Apple, `swiftlang`, the Swift Server Work Group, and similarly trusted core Swift projects when they simplify the code and make it easier to reason about. +- Commonly approved examples include `swift-configuration` and `swift-async-algorithms` when they reduce bespoke code and improve readability. +- For Apple app projects, prefer Apple-native logging facilities first and allow Swift Logging where it makes the project API clearer. +- Prefer Swift OpenTelemetry for telemetry and instrumentation when telemetry is needed, and prefer existing ecosystem integrations over bespoke wrappers. +- Prefer a checked-in repo-root `.swiftformat` file as the default Swift formatting source of truth, and prefer a pre-commit hook that formats staged Swift sources and then verifies them with `swiftformat --lint` before commit. +- Treat SwiftLint as an optional complementary signal layer for clarity, safety, and maintainability after SwiftFormat owns formatting shape. +- Keep automation and CI commands deterministic, non-interactive, and explicit about toolchain, platform, and configuration assumptions. + +## SwiftUI and State Architecture + +- Treat SwiftUI as declarative component UI, closer to React, F# Fabulous, and Elm than to imperative AppKit or UIKit code. Keep views self-contained, reactive, flexible, reusable, and easy to scan from top to bottom. +- Give each independently reusable view a declarative interface of plain values, narrow bindings, and action closures. Do not inject external ViewModels, stores, coordinators, managers, services, or other collaborating objects from one reusable view into another. +- Choose and record one explicit three-letter uppercase prefix for every app or package. Prefix project-owned Swift files and primary declarations; exempt only `Package.swift`, externally generated Swift, and vendored third-party Swift. +- Never use `+` in project-owned Swift filenames. Concatenate the owner and concern so Xcode navigation, rename, and refactoring keep one consistent grammar. +- Name views `GEAWhateverView.swift` and extracted modifiers `GEAWhateverViewModifier.swift`. Do not introduce ViewModel files as a SwiftUI default. +- Give independently editable or previewable view components their own files. Small private computed view properties or helper views may remain while they do not clutter focused editing or previews. +- Prefix extracted child components with their complete composition owner, such as `GEASettingsSheetToggleCard.swift`. +- Extract a custom `ViewModifier` after more than eight chained modifiers, or earlier when a coherent chain is reusable or obscures the view body. +- Prefer straight, top-down data flow with state owned at the narrowest view, scene, or app boundary that matches the behavior. +- Prefer `@State`, derived values, bindings, and small private helpers for component-local presentation state. When a component genuinely needs an observable state type, create and own it locally with `@State`; do not pass it to a separately reusable view. +- Do not build monolithic views, monolithic controllers, or broad shared mutable state when a smaller component boundary would be clearer. +- Keep updates to view-driving state minimal and localized. +- Prefer durable identity for types that drive SwiftUI state and view updates. +- Treat `App` as the application entry and scene composition boundary, `Scene` as the container for scene-specific lifecycle and environment, and `View` as the component rendering layer. +- Every native app target must have exactly one app lifecycle entry point: one `@main` app type, one `main.swift`, or the platform-equivalent single launch entry. Do not add alternate app entry points, second `@main` types, duplicate `main.swift` files, target-specific app entry files, or parallel app structs for variants. When launch behavior must differ by platform, configuration, or feature flag, keep the single entry point and use Swift conditional compilation or ordinary runtime conditionals inside that boundary. +- Use app-level lifecycle concerns at the `App` boundary, scene lifecycle concerns at the `Scene` boundary, and view-local active or presentation behavior inside views. +- Use `@Binding` to pass a focused writable piece of parent-owned state into a child view. +- Use `@Bindable` when working with an observable model that should project bindings to its mutable properties in a view. +- Use the dedicated SwiftData workflow for persistence architecture and its direct SwiftUI integration path. +- Prefer existing SwiftUI environment values and actions before inventing an equivalent router or service. Use environment values for shared context that truly belongs to the surrounding hierarchy, not as a dumping ground for unrelated dependencies. +- Model app capabilities as direct, concrete feature services. A service provides one capability or a cohesive group of related operations directly to the app; it talks directly to the framework, persistence, network, or system boundary that capability needs instead of forwarding through an app-service wrapper, repository stack, or manager chain. +- Create a feature service at the narrowest app or scene boundary that owns its lifecycle. Put a service into the SwiftUI environment only when independent descendants need to invoke it or observe its state directly. Keep a service private to its feature root when that is the only consumer. +- A service may be `@Observable` when the UI must observe its feature state. Otherwise prefer direct values, async operations, explicit errors, and narrow action closures. Reusable leaf views still receive only values, bindings, and action closures; never pass a service, repository, coordinator, manager, ViewModel, store, or other collaborator into their public interface. +- Keep services concrete by default. Introduce a protocol only for a demonstrated alternate implementation or boundary that cannot otherwise be tested; do not create protocol, adapter, or wrapper layers merely because a service exists. +- Add custom environment values or actions when a capability is dynamic across the hierarchy or shared by many independent components. Keep actions local to the owning component when only that component and its private child views use them. +- Use preference keys only to publish descendant-derived information upward to an ancestor, never as a general state bus. +- Prefer Swift's synthesized memberwise initializer for view properties. Do not write an explicit initializer unless it has real behavior beyond assigning those properties. +- Prefer key-path-based APIs, predicates, and sort descriptors when they keep data access direct and readable. +- Extract repeated chains of view modifiers into custom view modifiers early when that reduces clutter and clearly matches a view or family of views. + +## Xcode Workspace and Project Baseline + +- Treat the `.xcworkspace` or `.xcodeproj` as the source of truth for Apple platform app integration, schemes, build settings, destinations, and target membership. +- Prefer edits through Xcode-aware project structure and keep project file changes intentional and reviewed closely. +- Use the standard top-level Xcode app repository layout when creating or normalizing native app repos: `Sources/`, `Tests/`, `Shared/`, `Extensions/`, `Configurations/`, `Scripts/`, and `Packages/`. +- `Sources/` owns the main app target implementation and app-owned resources/support files. `Tests/` owns all test targets. `Shared/` owns reusable source intended to be compiled into the app and extension targets. `Extensions/` owns extension target roots, one folder per extension. `Configurations/` owns `.xcconfig` layers. `Scripts/` owns project-local automation and build helper scripts. `Packages/` owns local Swift packages only when a real package boundary is justified. +- Keep those top-level roots stable. Do not invent parallel names such as `AppSources`, `TestSources`, `Config`, `BuildScripts`, or `LocalPackages` for ordinary Xcode app repos unless the existing repo already has a deliberate, documented convention. +- Inside `Sources/`, use this strict app structure by default: `Views/`, `Models/`, and `Services/`. Do not create a root `Controllers/` directory. +- `Sources/Views/` owns SwiftUI views and UIKit/AppKit view surfaces. Use `Sources/Views/Shared`, `Sources/Views/macOS`, and `Sources/Views/iOS` so shared, macOS-specific, and iOS/iPadOS-specific UI have clear homes. +- Use bare prefixed names such as `GEAWhatever.swift` for runtime/domain values. Reserve `GEAWhateverModel.swift` for persistence, and use `GEAWhateverRecord.swift` or `GEAWhateverDTO.swift` only for genuinely additional representations. +- `Sources/Models/` owns Core Data and SwiftData persistence models plus additional record or transfer representations. +- `Sources/Services/` owns direct concrete feature and boundary services. Use `Consumed/` for external capabilities the app calls, `Internal/` for app-owned feature services, and `Provided/` for services the app exposes to extensions, helpers, plugins, integrations, or other clients. These directories describe ownership and direction; they do not justify wrapper layers or an app-wide service container. +- Name a service for its capability, such as `GEADownloadService.swift` or `GEAImportService.swift`. Do not create `GEAAppService.swift` as an umbrella service by default; `GEAApp.swift` remains the lifecycle-entry special case. +- Use `xcodebuild` for Apple platform integration validation, including scheme, destination or SDK, and configuration-specific build or test runs. +- Keep `xcodebuild` invocations reproducible in automation by passing explicit schemes, destinations or SDKs, and configurations when relevant. +- For Codex GUI worktree-first Xcode repos, use a portable `.codex/environments/*.toml` local environment file when the repo wants shared app setup or action buttons. Start from `apple-dev-skills/templates/codex-local-environments/xcode-project.toml`, keep paths repo-relative, and prefer `-derivedDataPath ./DerivedData` or another ignored repo-local build directory instead of user-global DerivedData. +- When scripts or terminal workflows add files on disk, verify that Xcode project membership, target membership, build-phase membership, and resource-bundle inclusion all match the intended result; files appearing in the directory tree alone are not enough. +- Direct filesystem edits outside `.pbxproj` are generally safe when Xcode is closed or when the current project is not open in Xcode, but still verify that the Xcode project picks up the intended files and memberships afterward. +- Prefer Debug builds for everyday edit-build-test loops, but validate Release builds explicitly when optimization, packaging, launch behavior, watchdog timing, or deployment realism matters. +- Treat tagged releases as a signal to validate both the normal Debug path and a Release artifact path, and when shipping apps or deliverables test the Release behavior without relying on an attached debugger. +- Prefer direct filesystem edits in Xcode-managed scope only when the workflow already accounts for project-file and scheme integrity. +- Never edit `.pbxproj` files directly. If a project-file change is needed and no safe project-aware tool is available, stop and ask for an Xcode-mediated project change instead. When `.pbxproj` is tracked and Xcode, XcodeGen, or another project-aware workflow legitimately changes it, treat that diff as critical project state: review it, stage it, and commit it with the branch before any push, merge, release, or cleanup. + +## XcodeGen and Build Configuration Defaults + +- For new Xcode app, framework, and workspace repositories, prefer an XcodeGen-backed project by default unless the user explicitly asks for a hand-managed Xcode project or the repository has a concrete reason to avoid a generator dependency. +- If the repo contains `project.yml`, `project.yaml`, or clearly named included XcodeGen spec files, treat the XcodeGen spec set as the source of truth for generated project structure. +- For XcodeGen-backed repos, make target membership, resource membership, schemes, Swift package declarations, test-plan references, project references, build configurations, configuration-file wiring, generation options, and project-level settings in the XcodeGen specs instead of editing the generated `.pbxproj`. +- Before running `xcodegen generate`, inspect the current git diff for generated `.xcodeproj` or `.pbxproj` changes. Treat existing project-file diffs as intentional user or Xcode GUI changes by default, not disposable generator drift. +- When Xcode GUI changes added build settings, signing settings, capabilities, `Info.plist` build setting overrides, file membership, scheme changes, or entitlement wiring to `.pbxproj`, preserve the user intent by moving each intentional value to the owning tracked source first: XcodeGen spec for structure, `.xcconfig` for build settings, `.entitlements` for entitlement keys, `Info.plist` for plist keys, `.xcscheme` or scheme spec for scheme behavior, and `.xctestplan` for test-plan content. +- Only regenerate after that promotion is complete, then review the generated project diff to confirm XcodeGen preserved the intended behavior instead of deleting it. If the owning tracked file is ambiguous, stop and ask before regenerating. +- For new XcodeGen-backed app scaffolds, start from the maintained `apple-dev-skills/templates/xcodegen/` templates when available instead of inventing a fresh project-spec shape from memory. +- Keep `minimumXcodeGenVersion` on a recent validated release for new scaffolds. Prefer updating the template and validation together when the repo intentionally raises the baseline. +- For Xcode 16 or newer project formats, prefer XcodeGen `syncedFolder` roots at the broad top-level directory boundary so file creation, deletion, and organization stay synchronized between Xcode and the filesystem without hand-listing every source file in YAML. +- Do not fragment ordinary XcodeGen source roots by subdirectory. A standard app target gets one `Sources` source entry that includes all app source, resource, support, generated plist, entitlement, and nested feature folders, plus one `Shared` source entry when shared app/extension code exists. A standard test target gets one `Tests` source entry that includes all test subdirectories. Extension targets use one `Extensions/` source entry per extension target. If a project has another separate top-level logical root, use one top-level entry for that root, not one entry per child folder. +- Never split `Sources/App`, `Sources/Resources`, `Sources/Support`, feature folders, or `Tests/Tests` into separate XcodeGen source entries unless a specific non-ordinary file or folder truly needs custom compiler flags, build-phase routing, destination filters, or target membership that cannot be represented from the broad root. +- If `syncedFolder` behaves poorly for a repo, fall back to the same broad top-level recursive paths such as `Sources`, `Tests`, or `Resources` with explicit `includes` and `excludes`; do not fall back to subdirectory-level fragmentation or one YAML entry per ordinary source file. +- Keep XcodeGen specs readable as project structure, not as a dumping ground for every build setting. Use `configs`, `configFiles`, `targets`, `schemes`, `packages`, `projectReferences`, `targetTemplates`, and `schemeTemplates` deliberately so future edits have an obvious owner. +- Prefer explicit top-level schemes for app scaffolds once scheme behavior matters. Put build, run, test, profile, analyze, archive, environment variables, command-line arguments, and test-plan references in the scheme spec rather than relying on hidden generated defaults. +- Prefer external `.xcconfig` files as the default home for nontrivial build settings. Keep build settings in XcodeGen inline settings only when they are small, local, and clearer there. +- Use `.xcconfig` files for settings that vary by Debug, Release, CI, local development, signing, bundle identity, compiler flags, Swift settings, deployment variants, or environment-specific behavior. +- Keep configuration layering explicit. Prefer a small shared base config, target-level configs for app/test/extension identity, then per-configuration configs that include the narrower target config and override only what changes. +- In XcodeGen specs, wire build configurations to their matching `.xcconfig` files instead of duplicating the same settings across generated project objects. +- Prefer checked-in external `.entitlements` files for app, extension, and capability-bearing targets, with `CODE_SIGN_ENTITLEMENTS` declared in the owning target's `.xcconfig`. Let Xcode capabilities update the entitlement plist when possible, then review and commit the entitlement diff; keep XcodeGen responsible for wiring the file, not regenerating its contents from inline YAML. +- Do not assume Xcode's Build Settings UI writes edited values back into `.xcconfig` files. When a build setting should remain tracked in `.xcconfig`, inspect the generated project diff after GUI changes and move intentional build-setting overrides from `.pbxproj` back into the owning `.xcconfig` before regenerating. +- Keep secrets, personal team IDs, local machine paths, provisioning profiles, API tokens, and private signing material out of committed `.xcconfig` files. Use build settings only for non-secret configuration values, safe placeholders, references to externally supplied values, or local developer placeholders that are safe to commit. +- Before changing generated project structure, inspect the root spec plus any `include` entries so the edit lands in the owning spec rather than duplicating settings in the wrong file. Remember that included specs merge into the root spec, and local overrides may intentionally replace arrays or maps. +- After changing XcodeGen specs, `.xcconfig` files, or entitlement-file wiring, run `xcodegen generate` from the spec root, or `xcodegen generate --spec ` when the project uses a non-default spec path. +- If the spec uses environment variables or generation hooks, preserve and document the required environment before regenerating so CI and other contributors can reproduce the project. +- Review the spec diff, `.xcconfig` diff, and generated `.xcodeproj` diff after regeneration. Generated `.pbxproj` changes are acceptable output when they come from XcodeGen, but they should still be reviewed for unintended target, scheme, signing, package, build-setting, or file-membership churn. +- Validate regenerated projects with explicit `xcodebuild` commands for the affected scheme, destination or SDK, and configuration. +- For existing hand-managed Xcode projects, do not migrate to XcodeGen or externalize build settings into `.xcconfig` files unless the user explicitly asks for that migration. When they do, treat it as a project-structure migration with before/after validation. diff --git a/skills/macos-privacy-permissions-workflow/references/validation-fixtures.md b/skills/macos-privacy-permissions-workflow/references/validation-fixtures.md new file mode 100644 index 00000000..51e17c82 --- /dev/null +++ b/skills/macos-privacy-permissions-workflow/references/validation-fixtures.md @@ -0,0 +1,19 @@ +# Privacy Permission Validation Fixtures + +## Minimum fixture matrix + +Use disposable, signed fixtures with one protected operation per mode: + +- Accessibility status/request plus one harmless AX read against a named target. +- A signed Apple Events controller and target so the controller-target pair is explicit. +- Screen-capture preflight/request and one bounded capture in a disposable guest. +- `EPDeveloperTool` status/request preserving all declared authorization states. +- The same development tool reached directly, from Terminal, an IDE, an agent host, and a helper/XPC process. +- One framework-owned personal-data class with correct, missing, and malformed usage descriptions. +- A Files and Folders or Full Disk Access denial that validates the Settings-managed boundary without attempting self-grant. + +## Test record + +Record fixture commit/hash, bundle ID, signer/Team ID/designated requirement, macOS build, SDK/Xcode, guest/physical status, management state, prior decision/reset history, invocation path, status/preflight, visible UI, lifecycle transition, exact error, and actual operation result. + +Automated checks may validate source declarations, signed identities, expected state handling, and reporting contracts. A visible prompt, System Settings edit, logout/restart, PPPC install, or live-host permission mutation requires separate explicit approval immediately before execution. Prefer a resettable SIP-enabled macOS guest; label local failure injection as lower fidelity. diff --git a/skills/macos-privacy-permissions-workflow/scripts/customization_config.py b/skills/macos-privacy-permissions-workflow/scripts/customization_config.py new file mode 100755 index 00000000..8474f269 --- /dev/null +++ b/skills/macos-privacy-permissions-workflow/scripts/customization_config.py @@ -0,0 +1,138 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.9" +# dependencies = ["PyYAML>=6.0.2,<7"] +# /// +"""Load and persist macOS privacy workflow customization state.""" + +from __future__ import annotations + +import argparse +import os +import re +import sys +from pathlib import Path + +import yaml + +SKILL_NAME = "macos-privacy-permissions-workflow" +CONFIG_HOME_ENV = "APPLE_DEV_SKILLS_CONFIG_HOME" +DEFAULT_CONFIG_ROOT = "~/.config/gaelic-ghost/apple-dev-skills" +ALLOWED_KEYS = {"schemaVersion", "isCustomized", "settings"} + + +def fail(message: str) -> None: + print(f"ERROR: {message}", file=sys.stderr) + raise SystemExit(1) + + +def load(path: Path, *, required: bool) -> dict: + if not path.exists(): + if required: + fail(f"Missing YAML file: {path}") + return {} + try: + data = yaml.safe_load(path.read_text(encoding="utf-8")) or {} + except yaml.YAMLError as error: + fail(f"Invalid YAML in {path}: {error}") + if not isinstance(data, dict): + fail(f"Top-level YAML document must be a mapping in {path}") + return data + + +def validate(data: dict, *, partial: bool) -> None: + unknown = set(data) - ALLOWED_KEYS + if unknown: + fail(f"Unknown top-level keys: {', '.join(sorted(unknown))}") + if not partial and set(data) != ALLOWED_KEYS: + fail("Customization state must define schemaVersion, isCustomized, and settings") + if "schemaVersion" in data and data["schemaVersion"] != 1: + fail("schemaVersion must be 1") + if "isCustomized" in data and not isinstance(data["isCustomized"], bool): + fail("isCustomized must be boolean") + if "settings" in data: + if not isinstance(data["settings"], dict): + fail("settings must be a mapping") + for key, value in data["settings"].items(): + if not re.fullmatch(r"[A-Za-z0-9_]+", str(key)): + fail(f"Invalid settings key: {key}") + if isinstance(value, (dict, list)): + fail(f"settings values must be scalar: {key}") + + +def template_path() -> Path: + return Path(__file__).resolve().parents[1] / "references" / "customization.template.yaml" + + +def durable_path() -> Path: + root = Path(os.environ.get(CONFIG_HOME_ENV, DEFAULT_CONFIG_ROOT)).expanduser() + return root / SKILL_NAME / "customization.yaml" + + +def effective() -> dict: + base = load(template_path(), required=True) + saved = load(durable_path(), required=False) + validate(base, partial=False) + validate(saved, partial=False) if saved else None + merged = { + "schemaVersion": saved.get("schemaVersion", base["schemaVersion"]), + "isCustomized": saved.get("isCustomized", base["isCustomized"]), + "settings": {**base["settings"], **saved.get("settings", {})}, + } + validate(merged, partial=False) + return merged + + +def render(data: dict) -> str: + return yaml.safe_dump(data, sort_keys=False, default_flow_style=False) + + +def command_path(_: argparse.Namespace) -> None: + print(durable_path()) + + +def command_effective(_: argparse.Namespace) -> None: + print(render(effective()), end="") + + +def command_apply(args: argparse.Namespace) -> None: + incoming = load(Path(args.input), required=True) + validate(incoming, partial=True) + current = effective() + updated = { + "schemaVersion": 1, + "isCustomized": True, + "settings": {**current["settings"], **incoming.get("settings", {})}, + } + validate(updated, partial=False) + target = durable_path() + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(render(updated), encoding="utf-8") + print(target) + + +def command_reset(_: argparse.Namespace) -> None: + target = durable_path() + if target.exists(): + target.unlink() + print(target) + + +def main() -> None: + parser = argparse.ArgumentParser(description="Manage macOS privacy workflow customization") + commands = parser.add_subparsers(dest="command", required=True) + path_parser = commands.add_parser("path") + path_parser.set_defaults(func=command_path) + effective_parser = commands.add_parser("effective") + effective_parser.set_defaults(func=command_effective) + apply_parser = commands.add_parser("apply") + apply_parser.add_argument("--input", required=True) + apply_parser.set_defaults(func=command_apply) + reset_parser = commands.add_parser("reset") + reset_parser.set_defaults(func=command_reset) + args = parser.parse_args() + args.func(args) + + +if __name__ == "__main__": + main() diff --git a/skills/macos-sandbox-file-access-workflow/SKILL.md b/skills/macos-sandbox-file-access-workflow/SKILL.md new file mode 100644 index 00000000..0e91e6bb --- /dev/null +++ b/skills/macos-sandbox-file-access-workflow/SKILL.md @@ -0,0 +1,74 @@ +--- +name: macos-sandbox-file-access-workflow +description: Design and diagnose macOS file access. Use for App Sandbox, App Groups, user selection, security-scoped bookmarks across relaunches, helpers or extensions, stale access, TCC overlap, POSIX or ACL, Data Vault, and SIP denials. +--- + +# macOS Sandbox File Access Workflow + +## Purpose + +Preserve user intent and access lifetime while selecting the smallest supported file-access mechanism. Treat a URL or path as resource identity, not durable authorization, and keep App Sandbox, TCC, POSIX, and mandatory controls distinct. + +## When To Use + +- Use when a sandboxed Mac app must open, save, import, export, drag, share, or persist access to files or directories. +- Use when access succeeds during selection but fails after relaunch, in a helper, or after a move/rename. +- Use to identify whether a remaining denial is sandbox, TCC, filesystem, volume, coordination, Data Vault, or SIP policy. + +## Single-Path Workflow + +1. Record the data owner, exact operation, resource type, read/write/execute need, persistence duration, process boundary, distribution channel, macOS build, and exact error. +2. Read `references/sandbox-and-filesystem-control-map.md` and identify every applicable control layer before choosing a capability. +3. Use the app container or a standard supported container-relative directory when it satisfies the feature. Use an App Group only for a real same-team shared-container requirement. +4. Prefer direct user selection through the appropriate open/save panel, document URL, drag/drop, or Photos/File Provider selection surface for external data. +5. Request only the user-selected read-only, read-write, or executable entitlement that the feature actually needs. Do not replace a narrow selection with Full Disk Access. +6. Create a security-scoped bookmark only when access must survive the current interaction or process lifetime. Follow every step in `references/security-scoped-bookmark-lifecycle.md`. +7. For helpers, XPC services, app extensions, or shared containers, use `references/helpers-groups-and-process-boundaries.md`; verify which process resolves and consumes authorization rather than passing a path and assuming authority follows. +8. Perform the narrow operation and balance every successful `startAccessingSecurityScopedResource()` with `stopAccessingSecurityScopedResource()`. Do not retain access indefinitely for convenience. +9. If access still fails, classify the exact denying layer: path resolution/symlink, ownership/mode/ACL, sandbox, TCC Files and Folders/Full Disk Access, mount/volume state, coordination, Data Vault, SIP, or service policy. +10. Validate relaunch, moved/renamed/removed resources, read-only enforcement, helper/extension behavior, revoked/inaccessible access, stale and malformed bookmark recovery, and privacy-safe logging using `references/validation-fixtures.md`. + +## Inputs + +- resource owner, selection path, operation, persistence need, and distribution channel +- app/helper/extension identities, sandbox entitlements, App Group, and signed artifacts +- bookmark creation/storage/resolution code and exact errors +- macOS build, volume/mount, POSIX/ACL, TCC, Data Vault, and SIP context + +## Outputs + +- selected access mechanism and least-privilege entitlement set +- bookmark ownership, storage, resolution, lifetime, and repair contract +- process-boundary authorization design +- exact denying layer, reproduced result, privacy-safe evidence, and unresolved gaps + +## Guards and Stop Conditions + +- Do not treat a path, URL, alias, file ID, or remote identifier as a durable authorization token. +- Do not store only a security-scoped URL or retain access indefinitely. +- Do not claim a bookmark bypasses TCC, Full Disk Access, Data Vaults, SIP, POSIX permissions, ACLs, mounts, or service policy. +- Do not log bookmark bytes or sensitive full paths without a specific privacy-reviewed diagnostic need. +- Do not use Finder Sync as a synchronization engine or access-grant mechanism. +- Stop when the resource owner, operation, persistence duration, or consuming process is unknown. + +## Fallbacks and Handoffs + +- Use `macos-privacy-permissions-workflow` for Files and Folders, Full Disk Access, or another TCC decision. +- Use `diagnose-apple-entitlements` when source, profile, or final signed sandbox/App Group entitlements disagree. +- Use `file-provider-and-finder-sync-workflow` for remote storage, File Provider domains, or Finder UI decoration. +- Use `app-extension-architecture-workflow` for extension lifecycle/IPC design and Xcode workflows for project edits. +- Use `research-macos-security-control` for private sandbox profiles, extensions, or exact-build Seatbelt behavior. + +## Customization + +Use `references/customization-flow.md`. The workflow has no runtime knobs; access scope must follow the recorded feature, process, resource, and lifetime. + +## References + +- `references/sandbox-and-filesystem-control-map.md` +- `references/security-scoped-bookmark-lifecycle.md` +- `references/helpers-groups-and-process-boundaries.md` +- `references/validation-fixtures.md` +- Recommend `references/snippets/apple-xcode-project-core.md` when implementing target entitlements or helper membership. +- [Protecting user data with App Sandbox](https://developer.apple.com/documentation/security/protecting-user-data-with-app-sandbox) +- [Accessing files from the macOS App Sandbox](https://developer.apple.com/documentation/security/accessing-files-from-the-macos-app-sandbox) diff --git a/skills/macos-sandbox-file-access-workflow/agents/openai.yaml b/skills/macos-sandbox-file-access-workflow/agents/openai.yaml new file mode 100644 index 00000000..1f09357d --- /dev/null +++ b/skills/macos-sandbox-file-access-workflow/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "macOS Sandbox File Access" + short_description: "Design durable sandboxed file access" + default_prompt: "Use $macos-sandbox-file-access-workflow to design the narrowest durable file-access path." diff --git a/skills/macos-sandbox-file-access-workflow/references/customization-flow.md b/skills/macos-sandbox-file-access-workflow/references/customization-flow.md new file mode 100644 index 00000000..8f5781c8 --- /dev/null +++ b/skills/macos-sandbox-file-access-workflow/references/customization-flow.md @@ -0,0 +1,5 @@ +# macOS Sandbox File Access Customization Contract + +The first version defines no runtime-enforced knobs. `scripts/customization_config.py` preserves the shared Apple Dev Skills customization contract; access scope must be selected from the concrete resource, process, operation, distribution, and persistence need. + +Inspect settings with `scripts/customization_config.py effective`, persist a documented change with `apply --input `, and verify the effective result afterward. diff --git a/skills/macos-sandbox-file-access-workflow/references/customization.template.yaml b/skills/macos-sandbox-file-access-workflow/references/customization.template.yaml new file mode 100644 index 00000000..cddd82d1 --- /dev/null +++ b/skills/macos-sandbox-file-access-workflow/references/customization.template.yaml @@ -0,0 +1,3 @@ +schemaVersion: 1 +isCustomized: false +settings: {} diff --git a/skills/macos-sandbox-file-access-workflow/references/helpers-groups-and-process-boundaries.md b/skills/macos-sandbox-file-access-workflow/references/helpers-groups-and-process-boundaries.md new file mode 100644 index 00000000..f2db778a --- /dev/null +++ b/skills/macos-sandbox-file-access-workflow/references/helpers-groups-and-process-boundaries.md @@ -0,0 +1,21 @@ +# Helpers, Groups, And Process Boundaries + +## App Groups + +Use an App Group only when separately signed targets from the same developer team need a documented shared container or service. Match the group identifier in tracked project capabilities, developer-account/profile authorization when applicable, and final entitlements of every consumer. An App Group does not grant access to arbitrary external paths. + +## Helpers and XPC services + +- Record which executable receives the user-selected URL, creates bookmark data, stores it, resolves it, starts access, and performs I/O. +- Do not pass a path across IPC and assume authorization follows. +- Prefer the parent process perform the file operation and exchange bounded data when that keeps authority narrower. +- If another process must consume the resource, verify the documented sandbox inheritance or bookmark transfer contract for that process type and distribution channel. +- Inspect the final signed entitlements and embedded profile of the helper/XPC service, not only the app target. + +## Extensions + +App extensions run in separate processes with their own entitlements, containers, lifecycle, and host-mediated inputs. Use extension-provided URLs only within their documented lifetime unless a supported bookmark contract says otherwise. Route extension architecture to `app-extension-architecture-workflow`. + +## Directory selection + +A user-selected directory may authorize descendants under the documented sandbox extension/bookmark behavior, subject to read/write scope and other controls. Do not generalize that to siblings, symlink escapes, other volumes, TCC-protected locations, or a remote identity model. diff --git a/skills/macos-sandbox-file-access-workflow/references/sandbox-and-filesystem-control-map.md b/skills/macos-sandbox-file-access-workflow/references/sandbox-and-filesystem-control-map.md new file mode 100644 index 00000000..4e84b42b --- /dev/null +++ b/skills/macos-sandbox-file-access-workflow/references/sandbox-and-filesystem-control-map.md @@ -0,0 +1,19 @@ +# Sandbox And Filesystem Control Map + +Evaluate controls in order and preserve the exact error at each boundary. + +| Layer | Question | Typical evidence | Correct owner | +| --- | --- | --- | --- | +| Resource identity | Does the URL still identify the intended file after move, rename, symlink, alias, volume remount, or replacement? | Standardized/resolved URL, resource identifiers, volume identity | App data model | +| POSIX and ACL | Does the process identity have discretionary access? | `stat`, `ls -le`, ownership/mode/ACL, exact `errno` | File owner/admin/user | +| App container | Does a container-relative location satisfy the feature? | Container path, bundle identity, sandbox container | App architecture | +| App Sandbox | Does the signed process have a static entitlement or current sandbox extension? | Final signed entitlements, process boundary, selection event, sandbox-denial log | Apple Dev workflow | +| Security-scoped bookmark | Was durable authorization created, stored, resolved, checked for staleness, and activated? | Bookmark lifecycle and Foundation errors | Apple Dev workflow | +| TCC | Is the location separately protected by Files and Folders or Full Disk Access? | Responsible code, public/Settings state, operation result | Privacy workflow | +| Mount/volume | Is the volume present, writable, unlocked, and compatible with the requested semantics? | Mount flags, filesystem, availability/eject state | App/OS/storage | +| Coordination/service | Does another process or service own coordinated access? | `NSFileCoordinator`/presenter or service error | Framework owner | +| Data Vault/SIP/mandatory policy | Is a mandatory system policy denying the operation despite root or discretionary permission? | Exact OS build, path class, logs, SIP/system state | Public docs or exact-build research | + +Static sandbox entitlements include the app container, documented standard-folder exceptions, App Groups, and user-selected access classes. A user interaction can issue a temporary sandbox extension; a security-scoped bookmark preserves supported authorization for later resolution. Neither is a universal filesystem capability. + +Downloads/media-folder entitlements are version- and distribution-sensitive. Verify the current [App Sandbox entitlement documentation](https://developer.apple.com/documentation/bundleresources/entitlements/com.apple.security.app-sandbox) and final signature before recommending one. diff --git a/skills/macos-sandbox-file-access-workflow/references/security-scoped-bookmark-lifecycle.md b/skills/macos-sandbox-file-access-workflow/references/security-scoped-bookmark-lifecycle.md new file mode 100644 index 00000000..e4ed082d --- /dev/null +++ b/skills/macos-sandbox-file-access-workflow/references/security-scoped-bookmark-lifecycle.md @@ -0,0 +1,47 @@ +# Security-Scoped Bookmark Lifecycle + +## Creation + +1. Receive a URL from a supported user-selection or document interaction. +2. Choose application-scoped or document-scoped behavior and read-only scope deliberately; verify the current platform API and entitlement requirements. +3. Create bookmark data with the appropriate security-scope options. +4. Store the bookmark bytes as sensitive authorization state. Associate them with a stable app record, not merely a path string. + +## Resolution and use + +1. Load bookmark data and resolve it with matching security-scope options. +2. Capture the stale result. If stale, recreate and persist bookmark data from the resolved URL before treating repair as complete. +3. Call `startAccessingSecurityScopedResource()` immediately around the narrow operation. +4. Balance a successful start with `stopAccessingSecurityScopedResource()` using structured cleanup such as `defer`. Do not stop when start returned false, and do not hold access for the app lifetime by default. +5. Preserve Foundation error domain/code/message and the later file-operation error separately. + +```swift +var stale = false +let url = try URL( + resolvingBookmarkData: data, + options: [.withSecurityScope], + relativeTo: nil, + bookmarkDataIsStale: &stale +) + +if stale { + let repaired = try url.bookmarkData( + options: [.withSecurityScope], + includingResourceValuesForKeys: nil, + relativeTo: nil + ) + try persist(repaired) +} + +let started = url.startAccessingSecurityScopedResource() +defer { + if started { url.stopAccessingSecurityScopedResource() } +} +try performNarrowOperation(at: url) +``` + +Adapt options and storage to the current documented API, sandbox shape, and read-only requirement. Validate selection-session access separately from post-relaunch bookmark access. + +## Failure matrix + +Test valid, stale, corrupt, missing, moved, renamed, removed, inaccessible, revoked, read-only, wrong-scope, wrong-process, and volume-offline cases. A resolved URL does not prove the file operation is authorized; another layer can still deny it. diff --git a/skills/macos-sandbox-file-access-workflow/references/snippets/apple-xcode-project-core.md b/skills/macos-sandbox-file-access-workflow/references/snippets/apple-xcode-project-core.md new file mode 100644 index 00000000..f161db8e --- /dev/null +++ b/skills/macos-sandbox-file-access-workflow/references/snippets/apple-xcode-project-core.md @@ -0,0 +1,142 @@ +# Apple Xcode Project Core AGENTS Snippet + +Use this snippet in repository `AGENTS.md` files when you want baseline standards for an existing native Apple app project managed through Xcode. + +## General Swift Baseline + +- For any Swift, Apple-framework, Apple-platform, SwiftUI, SwiftData, Observation, AppKit, UIKit, Foundation-on-Apple, or Xcode-related task, read the relevant Apple documentation first before planning, proposing, or making changes. +- For Apple, Swift, and Xcode documentation, use Xcode MCP `DocumentationSearch` first. Then use the Dash.app MCP when its installed docsets cover the question. Use Dash localhost HTTP only when the Dash.app MCP is unavailable or incomplete; use checked-out source, generated DocC, GitHub/source repositories, release notes, and readable online documentation only after those local MCP paths. Generic no-JS web search/open results, snippets, metadata shells, or bare Apple Developer URLs are not enough evidence that Apple docs were read. +- Before proposing an architecture or implementation, state the documented API behavior, lifecycle rule, or workflow requirement being relied on. +- Do not rely on memory, habit, or analogy as the primary source when Apple documentation exists. +- If Apple documentation and the current code disagree, stop and report the conflict before continuing. +- If no relevant Apple documentation can be found, say that explicitly before proceeding. +- Prefer the simplest correct Swift that is easiest to read, reason about, and maintain. +- Treat idiomatic Swift, Cocoa conventions, and modern Swift features as tools in service of readability, not as goals by themselves. +- Do not add ceremony, abstraction, or boilerplate just to make code look more architectural, more generic, or more "Swifty". +- Strongly prefer synthesized, implicit, and framework-provided behavior over custom code. +- Prefer synthesized conformances (`Codable`, `Equatable`, `Hashable`, etc.) whenever they satisfy the actual requirements. +- Prefer memberwise and otherwise synthesized initializers, default property values, and framework defaults over handwritten setup code. +- Do not add `CodingKeys`, manual `Codable` methods, custom initializers, wrappers, helper types, protocols, coordinators, or extra layers unless they are required by a concrete constraint or they make the final code clearly easier to understand. +- Prefer applicable existing framework or platform error types before inventing custom error wrappers or error hierarchies. +- Prefer direct, simple error flows and small focused error enums only when they materially improve understanding. +- Prefer stable, source-of-truth naming across layers when the data and meaning have not changed. +- Treat naming consistency as a reliability feature: if the same data still serves the same purpose, keep the same name. +- Do not rename fields just to match local style conventions when the external schema is already clear and stable. +- Do not use automatic case-conversion strategies such as `.convertFromSnakeCase` or `.convertToSnakeCase` unless the project explicitly wants that behavior and it clearly improves readability overall. +- When an API, cloud service, or wire format already provides clear names, preserve those names directly in Swift models and nearby code unless the meaning actually changes or a concrete collision must be resolved. +- Preserve raw wire and persistence shapes by default; do not add DTO, domain, or view-model conversion layers unless meaning actually changes or a concrete boundary requires it. +- Treat redundant wrappers, rename-and-copy layers, and duplicated logic as anti-patterns by default. +- This guidance is optimized for an advanced Swift reader and may prefer dense but readable modern Swift over beginner-style explicitness. +- Prefer explicit names that are consistent, unambiguous, and easy to scan at the call site. +- For public Swift APIs, treat streamlined, compact, ergonomic call sites as the only acceptable default; do not grow method families, overload sets, or loosely typed entry points when one clear typed API can express the operation. +- Prefer optional parameters with explicit default values over additional methods or overloads whenever the difference is optional behavior on the same operation. +- When a public function, initializer, or method reaches four or more arguments or parameters, strongly prefer a named typed `struct` request, options, or configuration value so call sites stay readable and future additions do not multiply overloads. +- Prefer enums, enum cases with associated values, and narrow typed values over strings, booleans, sentinel values, or parallel parameters whenever the domain has a closed or meaningful set of choices. +- Prefer compact syntax when it improves local reasoning, including shorthand syntax, ternary expressions, trailing closures, enums, `switch`, `map`, `filter`, `forEach`, async iteration, `AsyncSequence`, `AsyncStream`, and `AsyncAlgorithms`. +- Prefer explicit default values at initialization when they reduce optional-handling clutter and keep the code easier to follow. +- When lines, chains, or expressions get long, prefer chopping them down into a clean vertical, top-down structure with straight visual flow. +- Do not force value types by default, protocols at seams, actors by default, or other pattern slogans when a plainer concrete implementation is easier to reason about. +- Keep code compliant with Swift 6 language mode. +- Keep strict concurrency checking enabled. +- Prefer modern structured concurrency (`async`/`await`, task groups, actors) over legacy async patterns when it keeps the flow clearer and more direct. +- Make async code cancellation-aware and keep actor or task boundaries explicit instead of hiding them behind detached tasks or queue wrappers. +- Prefer clear `Sendable` boundaries for values that cross task or actor isolation, and keep unchecked sendability exceptional and justified locally. +- Prefer Swift Testing (`import Testing`) as the default test framework, and use XCTest only when a dependency or platform constraint requires it. +- Prefer Swift Testing for unit-style and package-style test surfaces in modern Xcode projects, including suites, tags, parameterized tests, and direct async tests. +- Use XCTest when the platform surface, dependency graph, or Apple tooling still expects it, and keep XCTest and Swift Testing responsibilities clearly separated when both coexist. +- Use XCUITest for UI automation, and prefer explicit element wait APIs such as `waitForExistence(timeout:)`, `waitForNonExistence(timeout:)`, and related state waits over fixed sleeps. +- Keep `.xctestplan` files versioned when test configurations, diagnostics, sanitizers, locale coverage, or selective plan execution matter, and inspect or run them explicitly with `xcodebuild -showTestPlans` and `xcodebuild -testPlan ...`. +- Prefer normal Xcode and XCTest parallel execution for ordinary Swift Testing, XCTest, and XCUITest runs when the project, scheme, destination, and test plan support it. Do not serialize regular tests just because they use Swift, XCTest, async tests, UI automation, or `.xctestplan` matrices. +- Treat tests that load large local AI or ML models, especially models over 500 million parameters, as heavy system-resource tests. Run those tests sequentially, one at a time. +- Prefer first-party and top-tier Swift ecosystem packages from Apple, `swiftlang`, the Swift Server Work Group, and similarly trusted core Swift projects when they simplify the code and make it easier to reason about. +- Commonly approved examples include `swift-configuration` and `swift-async-algorithms` when they reduce bespoke code and improve readability. +- For Apple app projects, prefer Apple-native logging facilities first and allow Swift Logging where it makes the project API clearer. +- Prefer Swift OpenTelemetry for telemetry and instrumentation when telemetry is needed, and prefer existing ecosystem integrations over bespoke wrappers. +- Prefer a checked-in repo-root `.swiftformat` file as the default Swift formatting source of truth, and prefer a pre-commit hook that formats staged Swift sources and then verifies them with `swiftformat --lint` before commit. +- Treat SwiftLint as an optional complementary signal layer for clarity, safety, and maintainability after SwiftFormat owns formatting shape. +- Keep automation and CI commands deterministic, non-interactive, and explicit about toolchain, platform, and configuration assumptions. + +## SwiftUI and State Architecture + +- Treat SwiftUI as declarative component UI, closer to React, F# Fabulous, and Elm than to imperative AppKit or UIKit code. Keep views self-contained, reactive, flexible, reusable, and easy to scan from top to bottom. +- Give each independently reusable view a declarative interface of plain values, narrow bindings, and action closures. Do not inject external ViewModels, stores, coordinators, managers, services, or other collaborating objects from one reusable view into another. +- Choose and record one explicit three-letter uppercase prefix for every app or package. Prefix project-owned Swift files and primary declarations; exempt only `Package.swift`, externally generated Swift, and vendored third-party Swift. +- Never use `+` in project-owned Swift filenames. Concatenate the owner and concern so Xcode navigation, rename, and refactoring keep one consistent grammar. +- Name views `GEAWhateverView.swift` and extracted modifiers `GEAWhateverViewModifier.swift`. Do not introduce ViewModel files as a SwiftUI default. +- Give independently editable or previewable view components their own files. Small private computed view properties or helper views may remain while they do not clutter focused editing or previews. +- Prefix extracted child components with their complete composition owner, such as `GEASettingsSheetToggleCard.swift`. +- Extract a custom `ViewModifier` after more than eight chained modifiers, or earlier when a coherent chain is reusable or obscures the view body. +- Prefer straight, top-down data flow with state owned at the narrowest view, scene, or app boundary that matches the behavior. +- Prefer `@State`, derived values, bindings, and small private helpers for component-local presentation state. When a component genuinely needs an observable state type, create and own it locally with `@State`; do not pass it to a separately reusable view. +- Do not build monolithic views, monolithic controllers, or broad shared mutable state when a smaller component boundary would be clearer. +- Keep updates to view-driving state minimal and localized. +- Prefer durable identity for types that drive SwiftUI state and view updates. +- Treat `App` as the application entry and scene composition boundary, `Scene` as the container for scene-specific lifecycle and environment, and `View` as the component rendering layer. +- Every native app target must have exactly one app lifecycle entry point: one `@main` app type, one `main.swift`, or the platform-equivalent single launch entry. Do not add alternate app entry points, second `@main` types, duplicate `main.swift` files, target-specific app entry files, or parallel app structs for variants. When launch behavior must differ by platform, configuration, or feature flag, keep the single entry point and use Swift conditional compilation or ordinary runtime conditionals inside that boundary. +- Use app-level lifecycle concerns at the `App` boundary, scene lifecycle concerns at the `Scene` boundary, and view-local active or presentation behavior inside views. +- Use `@Binding` to pass a focused writable piece of parent-owned state into a child view. +- Use `@Bindable` when working with an observable model that should project bindings to its mutable properties in a view. +- Use the dedicated SwiftData workflow for persistence architecture and its direct SwiftUI integration path. +- Prefer existing SwiftUI environment values and actions before inventing an equivalent router or service. Use environment values for shared context that truly belongs to the surrounding hierarchy, not as a dumping ground for unrelated dependencies. +- Model app capabilities as direct, concrete feature services. A service provides one capability or a cohesive group of related operations directly to the app; it talks directly to the framework, persistence, network, or system boundary that capability needs instead of forwarding through an app-service wrapper, repository stack, or manager chain. +- Create a feature service at the narrowest app or scene boundary that owns its lifecycle. Put a service into the SwiftUI environment only when independent descendants need to invoke it or observe its state directly. Keep a service private to its feature root when that is the only consumer. +- A service may be `@Observable` when the UI must observe its feature state. Otherwise prefer direct values, async operations, explicit errors, and narrow action closures. Reusable leaf views still receive only values, bindings, and action closures; never pass a service, repository, coordinator, manager, ViewModel, store, or other collaborator into their public interface. +- Keep services concrete by default. Introduce a protocol only for a demonstrated alternate implementation or boundary that cannot otherwise be tested; do not create protocol, adapter, or wrapper layers merely because a service exists. +- Add custom environment values or actions when a capability is dynamic across the hierarchy or shared by many independent components. Keep actions local to the owning component when only that component and its private child views use them. +- Use preference keys only to publish descendant-derived information upward to an ancestor, never as a general state bus. +- Prefer Swift's synthesized memberwise initializer for view properties. Do not write an explicit initializer unless it has real behavior beyond assigning those properties. +- Prefer key-path-based APIs, predicates, and sort descriptors when they keep data access direct and readable. +- Extract repeated chains of view modifiers into custom view modifiers early when that reduces clutter and clearly matches a view or family of views. + +## Xcode Workspace and Project Baseline + +- Treat the `.xcworkspace` or `.xcodeproj` as the source of truth for Apple platform app integration, schemes, build settings, destinations, and target membership. +- Prefer edits through Xcode-aware project structure and keep project file changes intentional and reviewed closely. +- Use the standard top-level Xcode app repository layout when creating or normalizing native app repos: `Sources/`, `Tests/`, `Shared/`, `Extensions/`, `Configurations/`, `Scripts/`, and `Packages/`. +- `Sources/` owns the main app target implementation and app-owned resources/support files. `Tests/` owns all test targets. `Shared/` owns reusable source intended to be compiled into the app and extension targets. `Extensions/` owns extension target roots, one folder per extension. `Configurations/` owns `.xcconfig` layers. `Scripts/` owns project-local automation and build helper scripts. `Packages/` owns local Swift packages only when a real package boundary is justified. +- Keep those top-level roots stable. Do not invent parallel names such as `AppSources`, `TestSources`, `Config`, `BuildScripts`, or `LocalPackages` for ordinary Xcode app repos unless the existing repo already has a deliberate, documented convention. +- Inside `Sources/`, use this strict app structure by default: `Views/`, `Models/`, and `Services/`. Do not create a root `Controllers/` directory. +- `Sources/Views/` owns SwiftUI views and UIKit/AppKit view surfaces. Use `Sources/Views/Shared`, `Sources/Views/macOS`, and `Sources/Views/iOS` so shared, macOS-specific, and iOS/iPadOS-specific UI have clear homes. +- Use bare prefixed names such as `GEAWhatever.swift` for runtime/domain values. Reserve `GEAWhateverModel.swift` for persistence, and use `GEAWhateverRecord.swift` or `GEAWhateverDTO.swift` only for genuinely additional representations. +- `Sources/Models/` owns Core Data and SwiftData persistence models plus additional record or transfer representations. +- `Sources/Services/` owns direct concrete feature and boundary services. Use `Consumed/` for external capabilities the app calls, `Internal/` for app-owned feature services, and `Provided/` for services the app exposes to extensions, helpers, plugins, integrations, or other clients. These directories describe ownership and direction; they do not justify wrapper layers or an app-wide service container. +- Name a service for its capability, such as `GEADownloadService.swift` or `GEAImportService.swift`. Do not create `GEAAppService.swift` as an umbrella service by default; `GEAApp.swift` remains the lifecycle-entry special case. +- Use `xcodebuild` for Apple platform integration validation, including scheme, destination or SDK, and configuration-specific build or test runs. +- Keep `xcodebuild` invocations reproducible in automation by passing explicit schemes, destinations or SDKs, and configurations when relevant. +- For Codex GUI worktree-first Xcode repos, use a portable `.codex/environments/*.toml` local environment file when the repo wants shared app setup or action buttons. Start from `apple-dev-skills/templates/codex-local-environments/xcode-project.toml`, keep paths repo-relative, and prefer `-derivedDataPath ./DerivedData` or another ignored repo-local build directory instead of user-global DerivedData. +- When scripts or terminal workflows add files on disk, verify that Xcode project membership, target membership, build-phase membership, and resource-bundle inclusion all match the intended result; files appearing in the directory tree alone are not enough. +- Direct filesystem edits outside `.pbxproj` are generally safe when Xcode is closed or when the current project is not open in Xcode, but still verify that the Xcode project picks up the intended files and memberships afterward. +- Prefer Debug builds for everyday edit-build-test loops, but validate Release builds explicitly when optimization, packaging, launch behavior, watchdog timing, or deployment realism matters. +- Treat tagged releases as a signal to validate both the normal Debug path and a Release artifact path, and when shipping apps or deliverables test the Release behavior without relying on an attached debugger. +- Prefer direct filesystem edits in Xcode-managed scope only when the workflow already accounts for project-file and scheme integrity. +- Never edit `.pbxproj` files directly. If a project-file change is needed and no safe project-aware tool is available, stop and ask for an Xcode-mediated project change instead. When `.pbxproj` is tracked and Xcode, XcodeGen, or another project-aware workflow legitimately changes it, treat that diff as critical project state: review it, stage it, and commit it with the branch before any push, merge, release, or cleanup. + +## XcodeGen and Build Configuration Defaults + +- For new Xcode app, framework, and workspace repositories, prefer an XcodeGen-backed project by default unless the user explicitly asks for a hand-managed Xcode project or the repository has a concrete reason to avoid a generator dependency. +- If the repo contains `project.yml`, `project.yaml`, or clearly named included XcodeGen spec files, treat the XcodeGen spec set as the source of truth for generated project structure. +- For XcodeGen-backed repos, make target membership, resource membership, schemes, Swift package declarations, test-plan references, project references, build configurations, configuration-file wiring, generation options, and project-level settings in the XcodeGen specs instead of editing the generated `.pbxproj`. +- Before running `xcodegen generate`, inspect the current git diff for generated `.xcodeproj` or `.pbxproj` changes. Treat existing project-file diffs as intentional user or Xcode GUI changes by default, not disposable generator drift. +- When Xcode GUI changes added build settings, signing settings, capabilities, `Info.plist` build setting overrides, file membership, scheme changes, or entitlement wiring to `.pbxproj`, preserve the user intent by moving each intentional value to the owning tracked source first: XcodeGen spec for structure, `.xcconfig` for build settings, `.entitlements` for entitlement keys, `Info.plist` for plist keys, `.xcscheme` or scheme spec for scheme behavior, and `.xctestplan` for test-plan content. +- Only regenerate after that promotion is complete, then review the generated project diff to confirm XcodeGen preserved the intended behavior instead of deleting it. If the owning tracked file is ambiguous, stop and ask before regenerating. +- For new XcodeGen-backed app scaffolds, start from the maintained `apple-dev-skills/templates/xcodegen/` templates when available instead of inventing a fresh project-spec shape from memory. +- Keep `minimumXcodeGenVersion` on a recent validated release for new scaffolds. Prefer updating the template and validation together when the repo intentionally raises the baseline. +- For Xcode 16 or newer project formats, prefer XcodeGen `syncedFolder` roots at the broad top-level directory boundary so file creation, deletion, and organization stay synchronized between Xcode and the filesystem without hand-listing every source file in YAML. +- Do not fragment ordinary XcodeGen source roots by subdirectory. A standard app target gets one `Sources` source entry that includes all app source, resource, support, generated plist, entitlement, and nested feature folders, plus one `Shared` source entry when shared app/extension code exists. A standard test target gets one `Tests` source entry that includes all test subdirectories. Extension targets use one `Extensions/` source entry per extension target. If a project has another separate top-level logical root, use one top-level entry for that root, not one entry per child folder. +- Never split `Sources/App`, `Sources/Resources`, `Sources/Support`, feature folders, or `Tests/Tests` into separate XcodeGen source entries unless a specific non-ordinary file or folder truly needs custom compiler flags, build-phase routing, destination filters, or target membership that cannot be represented from the broad root. +- If `syncedFolder` behaves poorly for a repo, fall back to the same broad top-level recursive paths such as `Sources`, `Tests`, or `Resources` with explicit `includes` and `excludes`; do not fall back to subdirectory-level fragmentation or one YAML entry per ordinary source file. +- Keep XcodeGen specs readable as project structure, not as a dumping ground for every build setting. Use `configs`, `configFiles`, `targets`, `schemes`, `packages`, `projectReferences`, `targetTemplates`, and `schemeTemplates` deliberately so future edits have an obvious owner. +- Prefer explicit top-level schemes for app scaffolds once scheme behavior matters. Put build, run, test, profile, analyze, archive, environment variables, command-line arguments, and test-plan references in the scheme spec rather than relying on hidden generated defaults. +- Prefer external `.xcconfig` files as the default home for nontrivial build settings. Keep build settings in XcodeGen inline settings only when they are small, local, and clearer there. +- Use `.xcconfig` files for settings that vary by Debug, Release, CI, local development, signing, bundle identity, compiler flags, Swift settings, deployment variants, or environment-specific behavior. +- Keep configuration layering explicit. Prefer a small shared base config, target-level configs for app/test/extension identity, then per-configuration configs that include the narrower target config and override only what changes. +- In XcodeGen specs, wire build configurations to their matching `.xcconfig` files instead of duplicating the same settings across generated project objects. +- Prefer checked-in external `.entitlements` files for app, extension, and capability-bearing targets, with `CODE_SIGN_ENTITLEMENTS` declared in the owning target's `.xcconfig`. Let Xcode capabilities update the entitlement plist when possible, then review and commit the entitlement diff; keep XcodeGen responsible for wiring the file, not regenerating its contents from inline YAML. +- Do not assume Xcode's Build Settings UI writes edited values back into `.xcconfig` files. When a build setting should remain tracked in `.xcconfig`, inspect the generated project diff after GUI changes and move intentional build-setting overrides from `.pbxproj` back into the owning `.xcconfig` before regenerating. +- Keep secrets, personal team IDs, local machine paths, provisioning profiles, API tokens, and private signing material out of committed `.xcconfig` files. Use build settings only for non-secret configuration values, safe placeholders, references to externally supplied values, or local developer placeholders that are safe to commit. +- Before changing generated project structure, inspect the root spec plus any `include` entries so the edit lands in the owning spec rather than duplicating settings in the wrong file. Remember that included specs merge into the root spec, and local overrides may intentionally replace arrays or maps. +- After changing XcodeGen specs, `.xcconfig` files, or entitlement-file wiring, run `xcodegen generate` from the spec root, or `xcodegen generate --spec ` when the project uses a non-default spec path. +- If the spec uses environment variables or generation hooks, preserve and document the required environment before regenerating so CI and other contributors can reproduce the project. +- Review the spec diff, `.xcconfig` diff, and generated `.xcodeproj` diff after regeneration. Generated `.pbxproj` changes are acceptable output when they come from XcodeGen, but they should still be reviewed for unintended target, scheme, signing, package, build-setting, or file-membership churn. +- Validate regenerated projects with explicit `xcodebuild` commands for the affected scheme, destination or SDK, and configuration. +- For existing hand-managed Xcode projects, do not migrate to XcodeGen or externalize build settings into `.xcconfig` files unless the user explicitly asks for that migration. When they do, treat it as a project-structure migration with before/after validation. diff --git a/skills/macos-sandbox-file-access-workflow/references/validation-fixtures.md b/skills/macos-sandbox-file-access-workflow/references/validation-fixtures.md new file mode 100644 index 00000000..f78d3915 --- /dev/null +++ b/skills/macos-sandbox-file-access-workflow/references/validation-fixtures.md @@ -0,0 +1,15 @@ +# Sandbox File Access Validation Fixtures + +Build a signed sandboxed fixture with open-panel selection and separate read-only/read-write modes. Persist bookmark data, terminate fully, relaunch, resolve, repair stale data, start access, perform one operation, and balance stop access. + +Cover: + +- file and directory selection; open/save, drag/drop, and document URLs +- selection-session access versus clean relaunch +- moved, renamed, removed, malformed, stale, revoked/inaccessible, and volume-offline resources +- read-only enforcement and attempted write +- main app, helper, XPC service, and extension consumers +- App Group match/mismatch across source, profile, and final signatures +- POSIX mode/ACL, symlink, mount, TCC-protected location, Data Vault, and SIP denials + +Record app and consumer identities, exact macOS build/SDK, sandbox and signed entitlements, selection source, bookmark options, stale/start results, exact Foundation and file errors, privacy-redacted path identity, operation result, and cleanup. Automated fixtures must use generated nonsensitive paths; visible prompts or Settings changes require explicit approval and preferably a disposable guest. diff --git a/skills/macos-sandbox-file-access-workflow/scripts/customization_config.py b/skills/macos-sandbox-file-access-workflow/scripts/customization_config.py new file mode 100755 index 00000000..7c8b797e --- /dev/null +++ b/skills/macos-sandbox-file-access-workflow/scripts/customization_config.py @@ -0,0 +1,104 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.9" +# dependencies = ["PyYAML>=6.0.2,<7"] +# /// +"""Load and persist sandbox file-access workflow customization state.""" + +from __future__ import annotations + +import argparse +import os +import re +import sys +from pathlib import Path + +import yaml + +SKILL_NAME = "macos-sandbox-file-access-workflow" +ROOT = "~/.config/gaelic-ghost/apple-dev-skills" +KEYS = {"schemaVersion", "isCustomized", "settings"} + + +def fail(message: str) -> None: + print(f"ERROR: {message}", file=sys.stderr) + raise SystemExit(1) + + +def read(path: Path, required: bool = False) -> dict: + if not path.exists(): + if required: + fail(f"Missing YAML file: {path}") + return {} + try: + value = yaml.safe_load(path.read_text(encoding="utf-8")) or {} + except yaml.YAMLError as error: + fail(f"Invalid YAML in {path}: {error}") + if not isinstance(value, dict): + fail(f"Top-level YAML document must be a mapping in {path}") + return value + + +def validate(value: dict, partial: bool = False) -> None: + if set(value) - KEYS: + fail(f"Unknown top-level keys: {', '.join(sorted(set(value) - KEYS))}") + if not partial and set(value) != KEYS: + fail("State must define schemaVersion, isCustomized, and settings") + if "schemaVersion" in value and value["schemaVersion"] != 1: + fail("schemaVersion must be 1") + if "isCustomized" in value and not isinstance(value["isCustomized"], bool): + fail("isCustomized must be boolean") + if "settings" in value: + if not isinstance(value["settings"], dict): + fail("settings must be a mapping") + for key, item in value["settings"].items(): + if not re.fullmatch(r"[A-Za-z0-9_]+", str(key)): + fail(f"Invalid settings key: {key}") + if isinstance(item, (dict, list)): + fail(f"settings values must be scalar: {key}") + + +def destination() -> Path: + root = Path(os.environ.get("APPLE_DEV_SKILLS_CONFIG_HOME", ROOT)).expanduser() + return root / SKILL_NAME / "customization.yaml" + + +def current() -> dict: + template = read(Path(__file__).resolve().parents[1] / "references/customization.template.yaml", True) + saved = read(destination()) + validate(template) + if saved: + validate(saved) + return {"schemaVersion": 1, "isCustomized": saved.get("isCustomized", False), "settings": {**template["settings"], **saved.get("settings", {})}} + + +def main() -> None: + parser = argparse.ArgumentParser(description="Manage sandbox file-access customization") + command = parser.add_subparsers(dest="command", required=True) + command.add_parser("path") + command.add_parser("effective") + apply = command.add_parser("apply") + apply.add_argument("--input", required=True) + command.add_parser("reset") + args = parser.parse_args() + target = destination() + if args.command == "path": + print(target) + elif args.command == "effective": + print(yaml.safe_dump(current(), sort_keys=False), end="") + elif args.command == "reset": + if target.exists(): + target.unlink() + print(target) + else: + incoming = read(Path(args.input), True) + validate(incoming, partial=True) + updated = {"schemaVersion": 1, "isCustomized": True, "settings": {**current()["settings"], **incoming.get("settings", {})}} + validate(updated) + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(yaml.safe_dump(updated, sort_keys=False), encoding="utf-8") + print(target) + + +if __name__ == "__main__": + main() diff --git a/skills/prepare-isolated-analysis-lab/SKILL.md b/skills/prepare-isolated-analysis-lab/SKILL.md index ef15110c..c20fc0ad 100644 --- a/skills/prepare-isolated-analysis-lab/SKILL.md +++ b/skills/prepare-isolated-analysis-lab/SKILL.md @@ -52,6 +52,7 @@ Return the approved isolation decision, selected profile, trusted-base identity, - Use `perform-dynamic-malware-analysis` for controlled execution and observation. - Use Reverse Engineering skills for exported binaries, disassembly, decompilation, and symbols. +- Use `reverse-engineering-skills:research-macos-security-control` for exact-build TCC, sandbox, entitlement, Gatekeeper, XProtect, SIP, or system-policy research that needs public/private evidence separation. - Use `apple-dev-skills:virtualization-framework-workflow` for custom VM implementation defects. - Use `apple-dev-skills:macos-development-vm-workflow` or `linux-development-vm-workflow` for benign guest provisioning and lifecycle mechanics. - Return to `select-analysis-isolation` when the chosen boundary fails fidelity or containment preflight. diff --git a/skills/research-macos-security-control/SKILL.md b/skills/research-macos-security-control/SKILL.md new file mode 100644 index 00000000..14b713d0 --- /dev/null +++ b/skills/research-macos-security-control/SKILL.md @@ -0,0 +1,57 @@ +--- +name: research-macos-security-control +description: Research one macOS security control on an exact build, separating public contracts, private evidence, and hypotheses. Use for TCC, sandbox, entitlements, Gatekeeper, XProtect, Hardened Runtime, SIP, or system-policy changes. +--- + +# Research macOS Security Control + +## Overview + +Answer one narrow control question on named artifacts and exact macOS builds. Start from supported public behavior, preserve originals, and label private symbols, schemas, strings, logs, and observed behavior as implementation evidence rather than stable API. + +## Workflow + +1. State the question and decision. + - Name the control, suspected behavior, affected actor/target, smallest falsifiable claim, expected decision, and stop condition. +2. Establish the evidence hierarchy. + - Read [references/source-and-evidence-hierarchy.md](references/source-and-evidence-hierarchy.md). + - Search Apple Platform Security, deployment/developer documentation, current SDK declarations, tool man pages, and checked-in source before private implementation. +3. Fix the environment and artifacts. + - Record hardware/architecture, exact macOS version/build, security-data/update state, selected SDK/Xcode, device management, host/guest/physical context, SIP/boot policy when relevant, and every artifact's path, hash/UUID, signing identity, acquisition source, and transformation history. +4. Classify the control. + - Use [references/control-research-matrix.md](references/control-research-matrix.md) to keep TCC, App Sandbox, entitlements, execution/distribution policy, malware protection, and system integrity distinct. +5. Inspect exact-build implementation without changing originals. + - Inspect relevant binaries/frameworks/services, Mach-O metadata, signatures/entitlements, dependencies, strings, symbols, XPC/interface metadata, launch/service ownership, focused unified logs, and existing Endpoint Security evidence. + - Use `evidence-notes-workflow`, `audit-apple-signing-and-containment`, and `compare-binary-versions` for their owned records. +6. Design the least invasive probe. + - Follow [references/exact-build-probe-design.md](references/exact-build-probe-design.md). Prefer a read-only/static check, then a bounded supported observation, then a disposable SIP-enabled guest. Require explicit approval for visible prompts, live-host permission mutations, re-signing, patching, protection changes, or sensitive capture. +7. Execute and preserve results. + - Record exact commands/tools/versions, inputs, timestamps, status/error/log fields, negative results and telemetry gaps, transformations, cleanup, and whether the observation occurred on host, guest, or physical Mac. +8. Compare builds correctly. + - Match architecture, artifact identity, security state, and analysis method. Say `changed between A and B` unless intermediate builds establish a tighter bound; do not infer causality from a symbol/string delta alone. +9. Write the technical note. + - Use [references/technical-note-contract.md](references/technical-note-contract.md). Separate public contract, direct observation, private evidence, hypothesis, conclusion/confidence, disproven explanations, and unresolved questions. +10. Route the result. + - Hand ordinary app privacy, file access, entitlement/provisioning, distribution, threat response, or formal reporting to the existing owning skill with the exact-build evidence record. + +## Guardrails + +- Do not present private symbols, `kTCCService*` constants, database schemas, log strings, sandbox profiles, or daemon behavior as supported public API. +- Do not mutate live TCC or system-policy databases for convenience. +- Do not disable SIP, boot protections, Gatekeeper, XProtect, or other controls without a separate exact goal, minimum necessary change, recorded before/after state, rollback, and explicit approval. +- Do not generalize one build, VM, architecture, security-data version, or transformed artifact to another without comparison evidence. +- Preserve originals and treat every extraction, thinning, re-sign, patch, or copy with changed metadata as a distinct artifact. +- Absence of a log/event is not proof that behavior did not occur when collection permission, retention, filter, or telemetry coverage is incomplete. + +## Output + +Return a technical note containing question/decision, public contract, environment and artifact identity, method/tooling, direct observations, private implementation evidence, hypotheses/tests, conclusions/confidence, build bounds, disproven explanations, mutations/rollback, fidelity gaps, and the next owning workflow. + +## Handoffs + +- `macos-privacy-permissions-workflow`: supported app-facing privacy implementation and responsible-code diagnosis. +- `macos-sandbox-file-access-workflow`: containers, user selection, bookmarks, App Groups, and supported persistent file access. +- `diagnose-apple-entitlements`: source/profile/signed/runtime comparison for ordinary products. +- `macos-distribution-workflow`: Gatekeeper/notarization/Hardened Runtime repair for exported products. +- `assess-macos-threat`, `inspect-macos-runtime-activity`, or `contain-and-recover-macos`: suspicious-host defensive work. +- `report-apple-security-research`: a formal reproducible security report after the technical finding exists. diff --git a/skills/research-macos-security-control/agents/openai.yaml b/skills/research-macos-security-control/agents/openai.yaml new file mode 100644 index 00000000..f8131f09 --- /dev/null +++ b/skills/research-macos-security-control/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Research macOS Security Control" + short_description: "Research one macOS control on an exact build" + default_prompt: "Use $research-macos-security-control to produce an exact-build technical note for this security control." diff --git a/skills/research-macos-security-control/references/control-research-matrix.md b/skills/research-macos-security-control/references/control-research-matrix.md new file mode 100644 index 00000000..fd054a4b --- /dev/null +++ b/skills/research-macos-security-control/references/control-research-matrix.md @@ -0,0 +1,12 @@ +# macOS Security Control Research Matrix + +| Control family | Public contract first | Private/exact-build evidence | Common confusion | +| --- | --- | --- | --- | +| TCC/privacy | Framework status/request APIs, System Settings, PPPC | TCC frameworks/services, attribution chains, private constants, schemas, logs | Usage description or entitlement is not consent; reset is not grant | +| App Sandbox/files | Container, documented entitlements, user selection, bookmarks | Seatbelt profiles/extensions, sandboxd/log behavior | Bookmark/path is not blanket access; TCC and mandatory controls remain | +| Entitlements/capabilities | Apple entitlement docs, account/profile rules | Private keys, platform-binary context, service checks | Signed declaration is not runtime authorization | +| Execution/distribution | Quarantine/provenance, signing, notarization, Gatekeeper, `syspolicy_check`/assessment docs | ExecutionPolicy/system-policy services, rule/evaluation internals | Gatekeeper, Hardened Runtime, Developer Tools, and malware response are distinct | +| Malware protection | Apple Platform Security, XProtect/update/Endpoint Security documentation | XProtect artifacts/config, remediation services, exact events/logs | Detection/block/remediation evidence does not alone prove execution or compromise | +| System integrity | SIP, signed system volume, recovery/boot security, system extensions | platform-binary policy, Data Vault enforcement, boot/service internals | Root/admin does not bypass mandatory controls | + +Also record cross-cutting identity (path, signer, Team ID, designated requirement, parent/helper), hardware/architecture, security-data version, management state, and artifact transformations. Use `syspolicy_check distribution` only for its documented assessment purpose and record tool output/version; do not conflate its combined checks into one root cause. diff --git a/skills/research-macos-security-control/references/exact-build-probe-design.md b/skills/research-macos-security-control/references/exact-build-probe-design.md new file mode 100644 index 00000000..b05b315d --- /dev/null +++ b/skills/research-macos-security-control/references/exact-build-probe-design.md @@ -0,0 +1,17 @@ +# Exact-Build Probe Design + +## Probe ladder + +1. Static/read-only: documentation, SDK, signature/entitlements, Mach-O/dyld metadata, symbols, strings, interface metadata, service ownership, existing logs. +2. Supported bounded observation: public preflight/status, one benign operation, focused log query, existing Endpoint Security telemetry. +3. Disposable SIP-enabled macOS guest: prompts, quarantine/Gatekeeper, signing identity, policy state, service restart, or repeatable failure injection. +4. Physical Mac or specialized environment: Secure Enclave, recoveryOS/boot policy, hardware, system/kernel extension, anti-VM, device, or customer-fidelity questions. +5. Explicitly approved transformation/protection change: only if lower steps cannot answer the narrow hypothesis. + +## Design record + +State the hypothesis, independent/dependent variables, exact actor/target/artifact/build, baseline, one intended change, expected confirming and contradicting result, required permission/telemetry, stop condition, cleanup, and fidelity limit. Preserve negative results with collection coverage. + +Do not prompt or mutate Gale's active Mac without immediate explicit approval. Do not use a broad terminal/agent Full Disk Access grant when a narrow signed fixture can answer the question. If a guest cannot reproduce hardware, boot, recovery, Data Vault, anti-VM, or customer state, label the result lower fidelity rather than compensating with stronger host mutations. + +For cross-build work, hold architecture, artifact role, signing class, security state, analysis tools, and probe method constant. Use `compare-binary-versions` to record correspondence and temporal bounds. diff --git a/skills/research-macos-security-control/references/source-and-evidence-hierarchy.md b/skills/research-macos-security-control/references/source-and-evidence-hierarchy.md new file mode 100644 index 00000000..70e951da --- /dev/null +++ b/skills/research-macos-security-control/references/source-and-evidence-hierarchy.md @@ -0,0 +1,14 @@ +# Source And Evidence Hierarchy + +Use the strongest applicable source and label its scope. + +1. Current Apple Platform Security, deployment, developer, support, and tool documentation. +2. Selected local SDK headers/module interfaces, command man pages/help, and Apple-open-source material for the exact release when available. +3. Exact-build original binaries/frameworks/services, code signatures, entitlements, provisioning, Mach-O/dyld metadata, exported symbols, and interface metadata. +4. Focused runtime observations, unified logs, Endpoint Security events, process ancestry, file/network effects, and exact errors from the recorded environment. +5. Matched cross-build comparison. +6. Hypothesis/inference supported by the above. + +Public documentation describes the supported contract but may omit implementation. SDK presence does not prove deployment availability. A private symbol or schema proves only that the recorded artifact contains it. A runtime success/failure proves only the recorded operation, artifact, identity, and environment. Multiple agreeing private observations strengthen a hypothesis but do not create a supported API. + +For each claim, cite the artifact/source and date/build. Keep copied excerpts minimal and preserve commands or exported metadata needed to reproduce the observation. diff --git a/skills/research-macos-security-control/references/technical-note-contract.md b/skills/research-macos-security-control/references/technical-note-contract.md new file mode 100644 index 00000000..db7e28f7 --- /dev/null +++ b/skills/research-macos-security-control/references/technical-note-contract.md @@ -0,0 +1,56 @@ +# macOS Security Control Technical Note Contract + +```markdown +# : + +## Decision Sought +- Question: +- Why it matters: +- Stop condition: + +## Environment +| Field | Value | +| --- | --- | +| Hardware / architecture | | +| macOS version / build | | +| SDK / Xcode | | +| Security update / management state | | +| Host, guest, or physical fidelity | | +| SIP / boot policy when relevant | | + +## Artifact Identity +| Artifact | Role | Hash / UUID | Signer / requirement | Source / transformation | +| --- | --- | --- | --- | --- | + +## Public Contract +- Apple/SDK source and dated behavior: + +## Method +- Tools and versions: +- Commands/probe: +- Permissions and telemetry coverage: +- Mutations, approval, rollback: + +## Direct Observations +- ... + +## Private Implementation Evidence +- ... (exact artifact/build; not public API) + +## Hypotheses And Tests +| Hypothesis | Test | Result | Status | +| --- | --- | --- | --- | + +## Conclusions +- Conclusion and confidence: +- Disproven explanations: +- Build/version bound: + +## Unresolved Questions And Fidelity Gaps +- ... + +## Handoff +- Owning workflow and next validation: +``` + +Use `evidence-notes-workflow` records for detailed session artifacts. Never merge observation and inference into one bullet. Say `not observed with recorded coverage` instead of `did not happen` when telemetry is incomplete. diff --git a/skills/select-analysis-isolation/SKILL.md b/skills/select-analysis-isolation/SKILL.md index c6eb69d2..d2a7454f 100644 --- a/skills/select-analysis-isolation/SKILL.md +++ b/skills/select-analysis-isolation/SKILL.md @@ -40,6 +40,7 @@ Read [references/isolation-matrix.md](references/isolation-matrix.md) before sel 7. Hand an approved execution boundary to `prepare-isolated-analysis-lab`. - Use `apple-dev-skills:choose-macos-virtualization-shape` when the development boundary is still undecided. - Use `apple-dev-skills:virtualization-framework-workflow` when a custom macOS or Linux VM host must be implemented or diagnosed. + - Use `reverse-engineering-skills:research-macos-security-control` when the lab must preserve an exact-build public/private control comparison and technical-note contract. - Treat a SIP-enabled macOS VM as the stable high-fidelity path for SIP-sensitive behavior; local sandbox, TCC, and failure injection are explicitly lower-fidelity approximations. ## Stop Conditions diff --git a/tests/test_macos_platform_security_forward_scenarios.py b/tests/test_macos_platform_security_forward_scenarios.py new file mode 100644 index 00000000..7b0953cc --- /dev/null +++ b/tests/test_macos_platform_security_forward_scenarios.py @@ -0,0 +1,78 @@ +from __future__ import annotations + +from pathlib import Path + +import pytest + + +ROOT = Path(__file__).resolve().parent.parent + + +def surface(plugin: str, skill: str, *references: str) -> str: + root = ROOT / "plugins" / plugin / "skills" / skill + paths = [root / "SKILL.md", *(root / "references" / name for name in references)] + return "\n".join(path.read_text(encoding="utf-8").lower() for path in paths) + + +@pytest.mark.parametrize( + ("plugin", "skill", "references", "phrases"), + [ + ( + "apple-dev-skills", + "macos-privacy-permissions-workflow", + ("responsible-code-and-attribution.md", "permission-class-matrix.md"), + ("helper or xpc", "axisprocesstrustedwithoptions", "responsible executable"), + ), + ( + "apple-dev-skills", + "macos-privacy-permissions-workflow", + ("permission-class-matrix.md",), + ("epdevelopertool.authorizationstatus", "requestaccess()", "do not promise ui"), + ), + ( + "apple-dev-skills", + "macos-privacy-permissions-workflow", + ("permission-class-matrix.md", "responsible-code-and-attribution.md"), + ("controller-target pair", "nsappleeventsusagedescription", "terminal"), + ), + ( + "apple-dev-skills", + "macos-sandbox-file-access-workflow", + ("security-scoped-bookmark-lifecycle.md",), + ("startaccessingsecurityscopedresource()", "stopaccessingsecurityscopedresource()", "if stale"), + ), + ( + "apple-dev-skills", + "diagnose-apple-entitlements", + ("five-state-entitlement-comparison.md", "artifact-and-nested-code-inspection.md"), + ("tracked source", "account authorization", "signed result", "runtime result", "helper"), + ), + ( + "apple-dev-skills", + "macos-sandbox-file-access-workflow", + ("sandbox-and-filesystem-control-map.md",), + ("posix and acl", "app sandbox", "tcc", "data vault/sip"), + ), + ( + "cybersecurity-skills", + "assess-macos-threat", + ("macos-security-layers.md",), + ("xprotect", "not automatically proof of prior execution", "research-macos-security-control"), + ), + ( + "reverse-engineering-skills", + "research-macos-security-control", + ("technical-note-contract.md", "source-and-evidence-hierarchy.md"), + ("private implementation evidence", "not public api", "exact macos version/build"), + ), + ], +) +def test_planned_forward_scenario_has_an_explicit_decision_path( + plugin: str, + skill: str, + references: tuple[str, ...], + phrases: tuple[str, ...], +) -> None: + contents = surface(plugin, skill, *references) + missing = [phrase for phrase in phrases if phrase not in contents] + assert not missing, f"{plugin}:{skill} is missing forward-test decisions: {missing}" diff --git a/uv.lock b/uv.lock index 2a6498da..a4af1e4b 100644 --- a/uv.lock +++ b/uv.lock @@ -286,7 +286,7 @@ wheels = [ [[package]] name = "socket-maintenance" -version = "9.20.0" +version = "9.21.0" source = { virtual = "." } [package.dev-dependencies]