From f695d3e52c8c95317125ed1f41089f13379b6a7c Mon Sep 17 00:00:00 2001 From: Gale W Date: Thu, 2 Jul 2026 09:40:49 -0400 Subject: [PATCH 1/3] docs: plan DeviceCheck App Attest workflow --- .../devicecheck-app-attest-skill-plan.md | 92 +++++++++++++++++++ plugins/apple-dev-skills/ROADMAP.md | 29 ++++++ 2 files changed, 121 insertions(+) create mode 100644 docs/maintainers/devicecheck-app-attest-skill-plan.md diff --git a/docs/maintainers/devicecheck-app-attest-skill-plan.md b/docs/maintainers/devicecheck-app-attest-skill-plan.md new file mode 100644 index 00000000..87d77626 --- /dev/null +++ b/docs/maintainers/devicecheck-app-attest-skill-plan.md @@ -0,0 +1,92 @@ +# DeviceCheck and App Attest Skill Plan + +This plan captures a candidate Apple Dev Skills expansion for the DeviceCheck framework, including per-device DeviceCheck state and App Attest app-instance validation. + +## Status + +Planned. The recommended first implementation is one focused workflow skill, `devicecheck-app-attest-workflow`, rather than separate `device-identification` and `app-attest` skills. + +## Ownership + +This skill belongs in `plugins/apple-dev-skills` because it depends on Apple framework behavior, app IDs, entitlements, Xcode signing state, Apple Developer account setup, local Apple documentation, and Apple server APIs. + +The skill should stay separate from the broader client auth and sync milestone. DeviceCheck and App Attest are risk and integrity signals for a server-backed app, not a general credential-storage or session-management workflow. + +The server verification side should be explicit but bounded. Apple Dev Skills can guide the client/server contract, challenge shape, App Attest object flow, and validation checklist, but server implementation should hand off to server-side Swift, OpenAPI, or RPC workflows when the backend code or API contract is the primary change. + +## Documented Apple Behavior To Rely On + +Apple documentation describes DeviceCheck as a framework plus Apple server APIs for reducing fraudulent use by managing device state and asserting app integrity. + +Device identification uses `DCDevice` in the app to generate an ephemeral token. The server uses that token with a JWT-backed Apple server request to query, update, or validate two per-device bits stored by Apple. The app must check `DCDevice.current.isSupported`, and the app must have an Apple Developer registered App ID. + +App Attest uses `DCAppAttestService` to generate a Secure Enclave-backed key, ask Apple to attest that key, and later generate assertions for sensitive server requests. The app must check `DCAppAttestService.shared.isSupported`, the app must have a registered App ID, and server-side challenge handling is required to prevent replay attacks. + +App Attest has important rollout and environment constraints: + +- Sandbox and production keys and receipts are separate. +- Distributed apps operate in production mode. +- Large existing user bases should ramp attestation gradually because attestation contacts Apple servers and can be rate limited. +- Attestation failures with `serverUnavailable` should retry later using the same key and `clientDataHash`. +- App Attest does not prove that a device operating system is uncompromised; it supplies one signal for a broader fraud-risk decision. +- On macOS, App Attest verification has macOS-specific signing identifier and key access-policy checks. + +## Proposed Skill + +### `devicecheck-app-attest-workflow` + +Use for DeviceCheck and App Attest decisions in Apple-platform apps, including `DCDevice`, per-device two-bit state, `DCAppAttestService`, App Attest key lifecycle, server challenge design, attestation and assertion request shapes, app IDs, entitlements, sandbox versus production environments, rollout/rate-limit planning, and client/server handoffs. + +This skill should help an agent: + +- classify whether the request is DeviceCheck two-bit device state, App Attest app-instance integrity, or a broader auth/session/sync concern +- apply the Apple docs gate before making current framework, entitlement, platform, or server-endpoint claims +- preserve the client/server boundary instead of pretending the app can validate itself +- keep key identifiers persistent but avoid storing secrets or treating attestation objects as app-side proof +- distinguish development, sandbox, TestFlight, App Store, Enterprise, Developer ID, and macOS signing behavior where Apple docs require it +- plan server challenges, replay protection, assertion counters, public-key storage, receipt storage, and risk metrics without making Apple Dev Skills own a backend implementation +- route Xcode signing, entitlements, App ID capability, build, run, simulator, device, and test follow-through to `xcode-build-run-workflow` or `xcode-testing-workflow` +- route generated client APIs to `swift-openapi-client-workflow` +- route backend validation implementation to the relevant server-side Swift or API-contract workflow when available + +## Skill Shape + +The first version should be guidance and routing, not a deterministic validator. App Attest server verification includes CBOR, COSE, ASN.1, certificate-chain, receipt, environment, signing-category, and counter checks, which are too stack-specific for a tiny first slice. + +Recommended first payload: + +- `SKILL.md` with the core workflow, docs gate, classification, handoffs, and guardrails. +- `agents/openai.yaml` metadata generated from the skill body. +- `references/devicecheck-device-state.md` for `DCDevice`, two-bit state, JWT, query/update/validate endpoints, privacy, and reset semantics. +- `references/app-attest-client-flow.md` for `DCAppAttestService`, key ID persistence, challenge hashing, attestation, assertions, `DCError`, and retry behavior. +- `references/app-attest-server-validation.md` for server-side validation checklist, receipt/risk metric handling, sandbox versus production, replay protection, counters, and macOS-specific validation notes. +- `references/entitlements-app-id-and-validation.md` for App ID, DeviceCheck capability, App Attest environment entitlement, provisioning, Xcode handoffs, simulator/device expectations, and rollout gates. + +Avoid scripts in the first slice unless a concrete backend stack needs one. If a later project repeatedly needs App Attest verification in Swift, add a separate deterministic reference implementation or test helper after the server-side owner is clear. + +## Implementation Slices + +1. Planning and docs evidence: + - Add this plan and roadmap milestone. + - Keep the plan grounded in Xcode and Dash documentation lookups. + - Decide the one-skill shape unless implementation evidence shows the workflow becomes too large. +2. Skill scaffold: + - Initialize `devicecheck-app-attest-workflow` under `plugins/apple-dev-skills/skills/`. + - Add references and generated `agents/openai.yaml`. + - Keep `SKILL.md` concise and move detailed validation checklists into references. +3. Metadata and inventory: + - Update `plugins/apple-dev-skills/.codex-plugin/plugin.json`. + - Update `plugins/apple-dev-skills/README.md` active skill inventory and prompt list. + - Update `plugins/apple-dev-skills/ROADMAP.md` status and ticket completion. +4. Tests and validation: + - Add targeted tests for frontmatter, routing boundaries, docs-gate language, server-handoff language, and metadata inventory. + - Run `bash .github/scripts/validate_repo_docs.sh` from `plugins/apple-dev-skills`. + - Run `uv run pytest` from `plugins/apple-dev-skills` when tests change. + - Run `uv run scripts/validate_socket_metadata.py` from the Socket root after metadata changes. + +## Open Questions + +- Should the first implementation name the skill `devicecheck-app-attest-workflow`, or should it use the broader `apple-app-integrity-workflow` name to leave room for future fraud-risk signals? +- Should server-validation guidance stay purely checklist-based at first, or should the initial skill include stack-specific examples for Swift server apps? +- Should DeviceCheck two-bit state and App Attest stay permanently in one skill, or should DeviceCheck split out later if two-bit state becomes common outside App Attest integrity flows? +- Should the first implementation include migration guidance for apps that already use custom device identifiers, receipt validation, or server-side abuse flags? diff --git a/plugins/apple-dev-skills/ROADMAP.md b/plugins/apple-dev-skills/ROADMAP.md index b193f33f..44961850 100644 --- a/plugins/apple-dev-skills/ROADMAP.md +++ b/plugins/apple-dev-skills/ROADMAP.md @@ -27,6 +27,7 @@ - [Milestone 49: Apple Media and Audio Workflow Skills](#milestone-49-apple-media-and-audio-workflow-skills) - [Milestone 50: Swift Lang Handoff And Compatibility](#milestone-50-swift-lang-handoff-and-compatibility) - [Milestone 52: Apple Design Animation And Symbols Workflow Skills](#milestone-52-apple-design-animation-and-symbols-workflow-skills) +- [Milestone 53: DeviceCheck and App Attest Workflow](#milestone-53-devicecheck-and-app-attest-workflow) - [Backlog Candidates](#backlog-candidates) - [History](#history) @@ -67,6 +68,7 @@ - Milestone 49: Apple Media and Audio Workflow Skills - Completed - Milestone 50: Swift Lang Handoff And Compatibility - In Progress - Milestone 52: Apple Design Animation And Symbols Workflow Skills - In Progress +- Milestone 53: DeviceCheck and App Attest Workflow - Planned ## Milestone 21: Swift Cleanup Automation Exploration @@ -733,6 +735,33 @@ In Progress - [x] Apple Dev Skills has focused first-party guidance for SF Symbols, SwiftUI animation, Core Animation, and Apple typography without blurring architecture, app-icon, accessibility, and Xcode execution ownership. - [x] The active skill inventory, plugin metadata, tests, and docs validator agree with the shipped design and animation workflow surface. +## Milestone 53: DeviceCheck and App Attest Workflow + +### Status + +Planned + +### Scope + +- [ ] Add a dedicated Apple workflow for DeviceCheck and App Attest adoption in iOS, macOS, and related Apple-platform apps. +- [ ] Keep `DCDevice` per-device two-bit state, `DCAppAttestService` key attestation, server challenges, assertions, receipts, fraud-risk metrics, App IDs, entitlements, sandbox/production behavior, rollout limits, and Xcode validation grounded in current Apple documentation. +- [ ] Keep app-side framework use and client/server contract guidance separate from backend implementation, generated API clients, general auth, Keychain storage, or app-sync ownership. + +### Tickets + +- [ ] Use [the DeviceCheck and App Attest skill plan](../../docs/maintainers/devicecheck-app-attest-skill-plan.md) as the implementation source of truth. +- [ ] Add `devicecheck-app-attest-workflow` with clear routing between DeviceCheck two-bit state, App Attest app-instance integrity, broader client auth, and server-side validation implementation. +- [ ] Add references for DeviceCheck device state, App Attest client flow, App Attest server validation, App ID and entitlement setup, sandbox/production behavior, rollout/rate-limit planning, and macOS-specific validation notes. +- [ ] Add skill interface metadata and update Apple Dev Skills plugin metadata, README active skill inventory, and default prompt list. +- [ ] Add targeted tests for skill frontmatter, docs-gate language, DeviceCheck/App Attest routing boundaries, server-handoff language, and metadata inventory. +- [ ] Run the Apple Dev Skills docs validator and pytest when the skill lands, then run the Socket metadata validator after plugin metadata changes. + +### Exit Criteria + +- [ ] The repository ships `devicecheck-app-attest-workflow` as the explicit owner for DeviceCheck and App Attest implementation-shape guidance. +- [ ] The workflow states the documented Apple behavior it relies on before proposing app, entitlement, server-challenge, attestation, assertion, receipt, or rollout changes. +- [ ] The workflow keeps server verification and API-contract implementation as explicit handoffs instead of hiding backend work inside Apple app guidance. + ## Backlog Candidates - [ ] Record plausible future work that is not yet committed to a milestone. From dee88190fd952dddb8073fc902b1130a6ac09e4b Mon Sep 17 00:00:00 2001 From: Gale W Date: Thu, 2 Jul 2026 09:53:43 -0400 Subject: [PATCH 2/3] plugin: add DeviceCheck App Attest workflow --- .../devicecheck-app-attest-skill-plan.md | 30 +-- .../.codex-plugin/plugin.json | 11 +- .../.github/scripts/sync_shared_snippets.sh | 1 + .../.github/scripts/validate_repo_docs.sh | 4 +- plugins/apple-dev-skills/README.md | 4 +- plugins/apple-dev-skills/ROADMAP.md | 30 +-- .../customization-consolidation-review.md | 6 +- .../devicecheck-app-attest-workflow/SKILL.md | 155 +++++++++++++ .../agents/openai.yaml | 4 + .../references/app-attest-client-flow.md | 76 +++++++ .../app-attest-server-validation.md | 86 +++++++ .../references/customization-flow.md | 30 +++ .../references/customization.template.yaml | 3 + .../references/devicecheck-device-state.md | 47 ++++ .../entitlements-app-id-and-validation.md | 63 ++++++ .../snippets/apple-xcode-project-core.md | 104 +++++++++ .../scripts/customization_config.py | 213 ++++++++++++++++++ ...test_customization_consolidation_review.py | 4 +- .../test_devicecheck_app_attest_workflow.py | 79 +++++++ 19 files changed, 911 insertions(+), 39 deletions(-) create mode 100644 plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/SKILL.md create mode 100644 plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/agents/openai.yaml create mode 100644 plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/app-attest-client-flow.md create mode 100644 plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/app-attest-server-validation.md create mode 100644 plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/customization-flow.md create mode 100644 plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/customization.template.yaml create mode 100644 plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/devicecheck-device-state.md create mode 100644 plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/entitlements-app-id-and-validation.md create mode 100644 plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/snippets/apple-xcode-project-core.md create mode 100755 plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/scripts/customization_config.py create mode 100644 plugins/apple-dev-skills/tests/test_devicecheck_app_attest_workflow.py diff --git a/docs/maintainers/devicecheck-app-attest-skill-plan.md b/docs/maintainers/devicecheck-app-attest-skill-plan.md index 87d77626..0e6fb88c 100644 --- a/docs/maintainers/devicecheck-app-attest-skill-plan.md +++ b/docs/maintainers/devicecheck-app-attest-skill-plan.md @@ -4,7 +4,7 @@ This plan captures a candidate Apple Dev Skills expansion for the DeviceCheck fr ## Status -Planned. The recommended first implementation is one focused workflow skill, `devicecheck-app-attest-workflow`, rather than separate `device-identification` and `app-attest` skills. +Implemented. The first implementation shipped one focused workflow skill, `devicecheck-app-attest-workflow`, rather than separate `device-identification` and `app-attest` skills. ## Ownership @@ -67,26 +67,26 @@ Avoid scripts in the first slice unless a concrete backend stack needs one. If a ## Implementation Slices 1. Planning and docs evidence: - - Add this plan and roadmap milestone. - - Keep the plan grounded in Xcode and Dash documentation lookups. - - Decide the one-skill shape unless implementation evidence shows the workflow becomes too large. + - [x] Add this plan and roadmap milestone. + - [x] Keep the plan grounded in Xcode and Dash documentation lookups. + - [x] Decide the one-skill shape unless implementation evidence shows the workflow becomes too large. 2. Skill scaffold: - - Initialize `devicecheck-app-attest-workflow` under `plugins/apple-dev-skills/skills/`. - - Add references and generated `agents/openai.yaml`. - - Keep `SKILL.md` concise and move detailed validation checklists into references. + - [x] Initialize `devicecheck-app-attest-workflow` under `plugins/apple-dev-skills/skills/`. + - [x] Add references and generated `agents/openai.yaml`. + - [x] Keep `SKILL.md` concise and move detailed validation checklists into references. 3. Metadata and inventory: - - Update `plugins/apple-dev-skills/.codex-plugin/plugin.json`. - - Update `plugins/apple-dev-skills/README.md` active skill inventory and prompt list. - - Update `plugins/apple-dev-skills/ROADMAP.md` status and ticket completion. + - [x] Update `plugins/apple-dev-skills/.codex-plugin/plugin.json`. + - [x] Update `plugins/apple-dev-skills/README.md` active skill inventory and prompt list. + - [x] Update `plugins/apple-dev-skills/ROADMAP.md` status and ticket completion. 4. Tests and validation: - - Add targeted tests for frontmatter, routing boundaries, docs-gate language, server-handoff language, and metadata inventory. - - Run `bash .github/scripts/validate_repo_docs.sh` from `plugins/apple-dev-skills`. - - Run `uv run pytest` from `plugins/apple-dev-skills` when tests change. - - Run `uv run scripts/validate_socket_metadata.py` from the Socket root after metadata changes. + - [x] Add targeted tests for frontmatter, routing boundaries, docs-gate language, server-handoff language, and metadata inventory. + - [x] Run `bash .github/scripts/validate_repo_docs.sh` from `plugins/apple-dev-skills`. + - [x] Run `uv run pytest` from `plugins/apple-dev-skills` when tests change. + - [x] Run `uv run scripts/validate_socket_metadata.py` from the Socket root after metadata changes. ## Open Questions -- Should the first implementation name the skill `devicecheck-app-attest-workflow`, or should it use the broader `apple-app-integrity-workflow` name to leave room for future fraud-risk signals? +- The first implementation uses `devicecheck-app-attest-workflow`; a broader `apple-app-integrity-workflow` can still be considered later if another Apple integrity signal needs a shared owner. - Should server-validation guidance stay purely checklist-based at first, or should the initial skill include stack-specific examples for Swift server apps? - Should DeviceCheck two-bit state and App Attest stay permanently in one skill, or should DeviceCheck split out later if two-bit state becomes common outside App Attest integrity flows? - Should the first implementation include migration guidance for apps that already use custom device identifiers, receipt validation, or server-side abuse flags? diff --git a/plugins/apple-dev-skills/.codex-plugin/plugin.json b/plugins/apple-dev-skills/.codex-plugin/plugin.json index abab013e..3041dc45 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": "7.6.0", - "description": "Apple development workflows for Codex, including media and audio repair, Xcode coding intelligence, SwiftUI animation and architecture, Core Animation, Apple typography, SF Symbols, AppKit architecture, Icon Composer app icons, Safari extensions, Swift OpenAPI clients, and DocC authoring guidance.", + "description": "Apple development workflows for Codex, including media and audio repair, Xcode coding intelligence, SwiftUI animation and architecture, Core Animation, Apple typography, SF Symbols, AppKit architecture, Icon Composer app icons, Safari extensions, DeviceCheck/App Attest, Swift OpenAPI clients, and DocC authoring guidance.", "author": { "name": "Gale", "email": "mail@galewilliams.com", @@ -33,6 +33,10 @@ "sf-symbols", "symbols", "safari", + "devicecheck", + "app-attest", + "attestation", + "fraud-risk", "openapi", "urlsession", "ios", @@ -42,8 +46,8 @@ "mcpServers": "./.mcp.json", "interface": { "displayName": "Apple Dev Skills", - "shortDescription": "Apple, Swift, media/audio repair, Xcode, SwiftUI, Core Animation, typography, SF Symbols, AppKit, Safari, OpenAPI client, and DocC workflows for Codex.", - "longDescription": "Bundle Apple-platform development skills for AVFAudio session repair, AVAudioEngine graph repair, AVFoundation media pipelines, Core Media timing and sample-buffer diagnostics, Core Audio modernization, strict Apple media type and framework selection, Xcode coding intelligence setup, Xcode-hosted agents, external-agent MCP access through xcrun mcpbridge, Swift, SwiftUI animation and architecture, Core Animation layer-backed rendering and animation, Apple typography and Dynamic Type, SF Symbols selection and custom-symbol workflows, AppKit architecture, Icon Composer app icon production, Safari extension, Safari Web Inspector, SafariServices integration, generated Swift OpenAPI clients with URLSession transport, Xcode, SwiftPM, DocC authoring and review, testing, formatting, and repository guidance work across iOS, macOS, and related Apple tooling. Most workflows work standalone; bootstrap and guidance-sync workflows that install or refresh repo-maintenance files require the companion Productivity Skills plugin, or the socket marketplace that installs both.", + "shortDescription": "Apple, Swift, media/audio repair, Xcode, SwiftUI, Core Animation, typography, SF Symbols, AppKit, Safari, DeviceCheck, App Attest, OpenAPI client, and DocC workflows for Codex.", + "longDescription": "Bundle Apple-platform development skills for AVFAudio session repair, AVAudioEngine graph repair, AVFoundation media pipelines, Core Media timing and sample-buffer diagnostics, Core Audio modernization, strict Apple media type and framework selection, Xcode coding intelligence setup, Xcode-hosted agents, external-agent MCP access through xcrun mcpbridge, Swift, SwiftUI animation and architecture, Core Animation layer-backed rendering and animation, Apple typography and Dynamic Type, SF Symbols selection and custom-symbol workflows, AppKit architecture, Icon Composer app icon production, Safari extension, Safari Web Inspector, SafariServices integration, DeviceCheck device-state and App Attest app-integrity planning, generated Swift OpenAPI clients with URLSession transport, Xcode, SwiftPM, DocC authoring and review, testing, formatting, and repository guidance work across iOS, macOS, and related Apple tooling. Most workflows work standalone; bootstrap and guidance-sync workflows that install or refresh repo-maintenance files require the companion Productivity Skills plugin, or the socket marketplace that installs both.", "developerName": "Gale", "category": "Developer Tools", "capabilities": [ @@ -61,6 +65,7 @@ "Set up Xcode coding intelligence, Xcode-hosted agents, external-agent MCP access through xcrun mcpbridge, and command/tool permission boundaries.", "Help me design and preview an Apple app icon using Icon Composer, local Mac artwork tools, ictool exports, and careful Computer Use guidance for the GUI.", "Choose the right Safari extension, Safari Web Inspector, SafariServices, messaging, content blocker, or automation fallback path for this Mac app.", + "Design a DeviceCheck or App Attest flow for this Apple app, keeping DCDevice, DCAppAttestService, server challenges, entitlements, rollout, and backend validation handoffs explicit.", "Add or diagnose a generated Swift OpenAPI client in this Apple app using OpenAPIURLSession and current Apple docs.", "Help me build, test, or debug this Swift or Xcode project using the repo's Apple workflows.", "Write or review DocC symbol comments, articles, extension files, and landing-page structure for this Swift repository.", diff --git a/plugins/apple-dev-skills/.github/scripts/sync_shared_snippets.sh b/plugins/apple-dev-skills/.github/scripts/sync_shared_snippets.sh index 4c2b8cc6..fad3877f 100755 --- a/plugins/apple-dev-skills/.github/scripts/sync_shared_snippets.sh +++ b/plugins/apple-dev-skills/.github/scripts/sync_shared_snippets.sh @@ -56,6 +56,7 @@ sync_one \ "$ROOT_DIR/skills/format-swift-sources/references/snippets/apple-xcode-project-core.md" \ "$ROOT_DIR/skills/explore-apple-swift-docs/references/snippets/apple-xcode-project-core.md" \ "$ROOT_DIR/skills/safari-extension-control-workflow/references/snippets/apple-xcode-project-core.md" \ + "$ROOT_DIR/skills/devicecheck-app-attest-workflow/references/snippets/apple-xcode-project-core.md" \ "$ROOT_DIR/skills/swiftui-app-architecture-workflow/references/snippets/apple-xcode-project-core.md" \ "$ROOT_DIR/skills/appkit-app-architecture-workflow/references/snippets/apple-xcode-project-core.md" \ "$ROOT_DIR/skills/sync-xcode-project-guidance/references/snippets/apple-xcode-project-core.md" \ 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 4b727936..e5a51c4a 100644 --- a/plugins/apple-dev-skills/.github/scripts/validate_repo_docs.sh +++ b/plugins/apple-dev-skills/.github/scripts/validate_repo_docs.sh @@ -123,6 +123,7 @@ active_skill_mds=( "./skills/sf-symbols-workflow/SKILL.md" "./skills/swiftui-animation-workflow/SKILL.md" "./skills/safari-extension-control-workflow/SKILL.md" + "./skills/devicecheck-app-attest-workflow/SKILL.md" "./skills/appkit-app-architecture-workflow/SKILL.md" "./skills/swiftui-app-architecture-workflow/SKILL.md" "./skills/apple-ui-accessibility-workflow/SKILL.md" @@ -135,7 +136,7 @@ active_skill_mds=( "./skills/sync-swift-package-guidance/SKILL.md" "./skills/xcode-coding-intelligence-workflow/SKILL.md" ) -[[ ${#active_skill_mds[@]} -eq 28 ]] || fail "Expected exactly 28 active skills, found ${#active_skill_mds[@]}." +[[ ${#active_skill_mds[@]} -eq 29 ]] || fail "Expected exactly 29 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" @@ -235,6 +236,7 @@ for file in \ "skills/sf-symbols-workflow/SKILL.md" \ "skills/swiftui-animation-workflow/SKILL.md" \ "skills/safari-extension-control-workflow/SKILL.md" \ + "skills/devicecheck-app-attest-workflow/SKILL.md" \ "skills/appkit-app-architecture-workflow/SKILL.md" \ "skills/swiftui-app-architecture-workflow/SKILL.md" \ "skills/sync-swift-package-guidance/SKILL.md" \ diff --git a/plugins/apple-dev-skills/README.md b/plugins/apple-dev-skills/README.md index 5777563f..f5db1b3b 100644 --- a/plugins/apple-dev-skills/README.md +++ b/plugins/apple-dev-skills/README.md @@ -1,6 +1,6 @@ # apple-dev-skills -Apple, Swift, SwiftUI animation and architecture, Core Animation, Apple typography, SF Symbols, AppKit, Icon Composer app icons, Safari, Xcode, Swift OpenAPI client, DocC, and `Dash.app` workflows for Codex. +Apple, Swift, SwiftUI animation and architecture, Core Animation, Apple typography, SF Symbols, AppKit, Icon Composer app icons, Safari, DeviceCheck, App Attest, Xcode, Swift OpenAPI client, DocC, and `Dash.app` workflows for Codex. ![Codex plugin directory filtered to the Socket marketplace, showing Apple Dev Skills listed alongside companion plugins below a Productivity Skills suggestion.](./docs/media/codex-plugin-directory-socket-apple-dev-skills.png) @@ -71,6 +71,7 @@ Use Apple Dev Skills when an agent is helping with: - Xcode coding intelligence, Xcode-hosted agents, and external-agent MCP setup - Icon Composer app icon design, preview, and Xcode handoff - Safari extension and SafariServices integration choices +- DeviceCheck per-device state and App Attest app-integrity flow planning - Swift OpenAPI client generation and `URLSession` transport integration - Swift package bootstrap, build, and testing - Apple UI accessibility work @@ -137,6 +138,7 @@ uv run pytest - `coreaudio-modernization-repair-workflow` - `core-animation-layer-workflow` - `coremedia-timing-samplebuffer-workflow` +- `devicecheck-app-attest-workflow` - `explore-apple-swift-docs` - `format-swift-sources` - `icon-composer-app-icon-workflow` diff --git a/plugins/apple-dev-skills/ROADMAP.md b/plugins/apple-dev-skills/ROADMAP.md index 44961850..07561bef 100644 --- a/plugins/apple-dev-skills/ROADMAP.md +++ b/plugins/apple-dev-skills/ROADMAP.md @@ -68,7 +68,7 @@ - Milestone 49: Apple Media and Audio Workflow Skills - Completed - Milestone 50: Swift Lang Handoff And Compatibility - In Progress - Milestone 52: Apple Design Animation And Symbols Workflow Skills - In Progress -- Milestone 53: DeviceCheck and App Attest Workflow - Planned +- Milestone 53: DeviceCheck and App Attest Workflow - Completed ## Milestone 21: Swift Cleanup Automation Exploration @@ -739,28 +739,30 @@ In Progress ### Status -Planned +Completed ### Scope -- [ ] Add a dedicated Apple workflow for DeviceCheck and App Attest adoption in iOS, macOS, and related Apple-platform apps. -- [ ] Keep `DCDevice` per-device two-bit state, `DCAppAttestService` key attestation, server challenges, assertions, receipts, fraud-risk metrics, App IDs, entitlements, sandbox/production behavior, rollout limits, and Xcode validation grounded in current Apple documentation. -- [ ] Keep app-side framework use and client/server contract guidance separate from backend implementation, generated API clients, general auth, Keychain storage, or app-sync ownership. +- [x] Add a dedicated Apple workflow for DeviceCheck and App Attest adoption in iOS, macOS, and related Apple-platform apps. +- [x] Keep `DCDevice` per-device two-bit state, `DCAppAttestService` key attestation, server challenges, assertions, receipts, fraud-risk metrics, App IDs, entitlements, sandbox/production behavior, rollout limits, and Xcode validation grounded in current Apple documentation. +- [x] Keep app-side framework use and client/server contract guidance separate from backend implementation, generated API clients, general auth, Keychain storage, or app-sync ownership. ### Tickets -- [ ] Use [the DeviceCheck and App Attest skill plan](../../docs/maintainers/devicecheck-app-attest-skill-plan.md) as the implementation source of truth. -- [ ] Add `devicecheck-app-attest-workflow` with clear routing between DeviceCheck two-bit state, App Attest app-instance integrity, broader client auth, and server-side validation implementation. -- [ ] Add references for DeviceCheck device state, App Attest client flow, App Attest server validation, App ID and entitlement setup, sandbox/production behavior, rollout/rate-limit planning, and macOS-specific validation notes. -- [ ] Add skill interface metadata and update Apple Dev Skills plugin metadata, README active skill inventory, and default prompt list. -- [ ] Add targeted tests for skill frontmatter, docs-gate language, DeviceCheck/App Attest routing boundaries, server-handoff language, and metadata inventory. -- [ ] Run the Apple Dev Skills docs validator and pytest when the skill lands, then run the Socket metadata validator after plugin metadata changes. +- [x] Use [the DeviceCheck and App Attest skill plan](../../docs/maintainers/devicecheck-app-attest-skill-plan.md) as the implementation source of truth. +- [x] Add `devicecheck-app-attest-workflow` with clear routing between DeviceCheck two-bit state, App Attest app-instance integrity, broader client auth, and server-side validation implementation. +- [x] Add references for DeviceCheck device state, App Attest client flow, App Attest server validation, App ID and entitlement setup, sandbox/production behavior, rollout/rate-limit planning, and macOS-specific validation notes. +- [x] Add skill interface metadata and update Apple Dev Skills plugin metadata, README active skill inventory, and default prompt list. +- [x] Add targeted tests for skill frontmatter, docs-gate language, DeviceCheck/App Attest routing boundaries, server-handoff language, and metadata inventory. +- [x] Run the Apple Dev Skills docs validator and pytest when the skill lands, then run the Socket metadata validator after plugin metadata changes. ### Exit Criteria -- [ ] The repository ships `devicecheck-app-attest-workflow` as the explicit owner for DeviceCheck and App Attest implementation-shape guidance. -- [ ] The workflow states the documented Apple behavior it relies on before proposing app, entitlement, server-challenge, attestation, assertion, receipt, or rollout changes. -- [ ] The workflow keeps server verification and API-contract implementation as explicit handoffs instead of hiding backend work inside Apple app guidance. +- [x] The repository ships `devicecheck-app-attest-workflow` as the explicit owner for DeviceCheck and App Attest implementation-shape guidance. +- [x] The workflow states the documented Apple behavior it relies on before proposing app, entitlement, server-challenge, attestation, assertion, receipt, or rollout changes. +- [x] The workflow keeps server verification and API-contract implementation as explicit handoffs instead of hiding backend work inside Apple app guidance. + +Completed Milestone 53 by adding `devicecheck-app-attest-workflow`, focused references for DeviceCheck state, App Attest client flow, server validation, and App ID/entitlement validation, plus plugin metadata, README inventory, shared snippet coverage, customization contract files, and targeted tests for routing, docs gates, and handoffs. ## Backlog Candidates 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 3691e930..974dc28b 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 `28` separate `references/customization.template.yaml` files. -- The active skill surface ships `28` separate `scripts/customization_config.py` entrypoints. +- The active skill surface ships `29` separate `references/customization.template.yaml` files. +- The active skill surface ships `29` 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 `apple-ui-accessibility-workflow`, `safari-extension-control-workflow`, `swiftui-app-architecture-workflow`, `swiftui-animation-workflow`, `sf-symbols-workflow`, `core-animation-layer-workflow`, `apple-typography-workflow`, `appkit-app-architecture-workflow`, `xcode-coding-intelligence-workflow`, `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 `apple-ui-accessibility-workflow`, `safari-extension-control-workflow`, `devicecheck-app-attest-workflow`, `swiftui-app-architecture-workflow`, `swiftui-animation-workflow`, `sf-symbols-workflow`, `core-animation-layer-workflow`, `apple-typography-workflow`, `appkit-app-architecture-workflow`, `xcode-coding-intelligence-workflow`, `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/skills/devicecheck-app-attest-workflow/SKILL.md b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/SKILL.md new file mode 100644 index 00000000..ebfbaa26 --- /dev/null +++ b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/SKILL.md @@ -0,0 +1,155 @@ +--- +name: devicecheck-app-attest-workflow +description: Guide DeviceCheck and App Attest adoption in Apple-platform apps using DCDevice, DCAppAttestService, app IDs, entitlements, server challenges, attestation objects, assertions, receipts, fraud-risk metrics, sandbox/production environments, rollout planning, and explicit client/server handoffs. Use when implementing or diagnosing DeviceCheck per-device two-bit state, App Attest app-instance integrity, Apple server API validation, App Attest environment setup, macOS App Attest verification, App Clip key-sharing, supported extension contexts, or fraud-risk integration that must be checked against current Apple documentation. +--- + +# DeviceCheck App Attest Workflow + +## Purpose + +Guide DeviceCheck and App Attest implementation decisions without confusing app-side Apple framework calls with server-side trust decisions. + +The practical decision is whether the app needs DeviceCheck two-bit device state, App Attest app-instance integrity, both signals, or a different auth/session/sync workflow. The skill keeps Apple docs, Xcode signing state, server challenges, replay protection, rollout constraints, and backend handoffs visible before implementation starts. + +## When To Use + +- Use this skill when adding or diagnosing `DCDevice`, `generateToken(completionHandler:)`, Apple DeviceCheck query/update/validate endpoints, or the two per-device bits Apple stores for an app. +- Use this skill when adding or diagnosing `DCAppAttestService`, `generateKey(completionHandler:)`, `attestKey(_:clientDataHash:completionHandler:)`, `generateAssertion(_:clientDataHash:completionHandler:)`, or `DCError`. +- Use this skill when the work involves App Attest App ID registration, DeviceCheck capabilities, the `com.apple.developer.devicecheck.appattest-environment` entitlement, sandbox versus production behavior, TestFlight or App Store rollout, Enterprise distribution, Developer ID, or macOS signing validation. +- Use this skill when the app and server need a challenge, attestation, assertion, receipt, public-key, counter, or fraud-risk metric contract. +- Use this skill when replacing custom device identifiers, local-only jailbreak checks, receipt-only abuse checks, or ad hoc risk flags with Apple-supported DeviceCheck or App Attest signals. +- Recommend `swift-openapi-client-workflow` when the primary task is generated API client setup for the app-to-server transport. +- Recommend `xcode-build-run-workflow` when the next step is target setup, entitlements, signing, App ID capability wiring, build, run, simulator, device, or guarded Xcode project mutation. +- Recommend `xcode-testing-workflow` when the next step is repeatable XCTest, XCUITest, simulator/device matrix checks, or test-plan setup. +- Recommend server-side Swift, OpenAPI, RPC, or backend-specific workflows when the primary task is implementing server verification, persistence, JWT generation, API routes, or fraud-risk policy. +- Recommend the broader client auth and sync workflow when the request is really Keychain storage, Sign in with Apple, `ASWebAuthenticationSession`, token refresh, logout, multi-account state, or app sync. + +## Single-Path Workflow + +1. Classify the integrity request: + - DeviceCheck two-bit state with `DCDevice` + - App Attest app-instance integrity with `DCAppAttestService` + - combined DeviceCheck plus App Attest risk signal + - App ID, entitlement, signing, or environment setup + - server verification, receipt, counter, or fraud metric work + - broader auth, Keychain, token refresh, generated client, or app-sync work +2. Apply the Apple docs gate before recommending shape: + - read the relevant DeviceCheck, App Attest, entitlement, CryptoKit, code-signing, or platform documentation first + - state the documented Apple behavior being relied on + - if Apple docs and current code disagree, stop and surface that conflict + - if no relevant Apple documentation can be found, say that explicitly before proceeding +3. Choose the supported signal: + - use DeviceCheck when the server needs Apple-hosted per-device two-bit state for a narrow abuse, promotion, or fraud flag + - use App Attest when the server needs evidence that a request comes from a legitimate app instance using an attested key + - use both only when the risk policy has a concrete reason to combine per-device state with app-instance assertions + - do not use either as a replacement for user authentication, authorization, server-side rate limiting, or normal abuse monitoring +4. Plan the client/server boundary: + - app checks availability and requests server challenges + - app generates DeviceCheck tokens, App Attest keys, attestations, or assertions + - server verifies tokens, attestations, assertions, receipts, counters, app identifiers, environments, and replay protections + - server owns the risk decision and user-visible fallback behavior +5. Plan storage and lifecycle: + - persist App Attest key identifiers because the private key is not directly readable and the key ID cannot be recovered later + - do not persist server challenges for reuse + - keep development/sandbox and production App Attest records separate + - expect App Attest keys to survive ordinary app updates but not reinstall, migration, or device restore + - keep DeviceCheck bit meanings documented server-side +6. Plan rollout and validation: + - handle unsupported devices gracefully on both client and server + - model sandbox and production endpoint differences before rollout + - avoid immediate large-population App Attest onboarding when Apple guidance calls for ramping + - route Xcode signing, entitlements, build, run, simulator, and device checks to Xcode skills +7. Return one recommendation path with: + - selected signal + - documented Apple behavior relied on + - app calls and storage plan + - server verification and persistence plan + - environment and entitlement plan + - validation and rollout plan + - explicit handoffs for Xcode, generated clients, backend implementation, broader auth, or docs lookup + +## Inputs + +- `request`: optional free-text DeviceCheck or App Attest task. +- `signal_goal`: optional emphasis such as `device-state`, `app-integrity`, `combined-risk`, `entitlement-setup`, `server-validation`, or `unknown`. +- `platform_context`: optional emphasis such as `ios`, `macos`, `watchos`, `tvos`, `visionos`, `app-clip`, `extension`, or `mixed-apple`. +- `distribution_context`: optional emphasis such as `development`, `sandbox`, `testflight`, `app-store`, `enterprise`, `developer-id`, or `unknown`. +- `server_context`: optional backend shape such as `swift-server`, `openapi`, `rpc`, `node`, `python`, `existing-api`, or `unknown`. +- Defaults: + - docs-first guidance always applies + - prefer one signal until the risk policy justifies combining them + - keep app-side framework calls and server-side trust decisions separate + - route Xcode state mutation and backend implementation to the owning workflow + +## Outputs + +- `status` + - `success`: the request belongs to this workflow and a DeviceCheck or App Attest recommendation is ready + - `handoff`: the request belongs to another workflow after DeviceCheck/App Attest-aware classification + - `blocked`: the request lacks enough app, server, entitlement, environment, or docs evidence for a trustworthy recommendation +- `path_type` + - `devicecheck`: the recommendation uses `DCDevice` and Apple DeviceCheck server APIs + - `app-attest`: the recommendation uses `DCAppAttestService` and App Attest server verification + - `combined`: the recommendation intentionally combines DeviceCheck and App Attest risk signals + - `handoff`: the recommendation belongs to Xcode, generated client, backend, broader auth, sync, or docs workflow +- `output` + - selected signal and reason + - documented Apple behavior relied on + - app-side framework calls and storage lifecycle + - server challenge, verification, persistence, and replay-protection plan + - App ID, entitlement, signing, environment, and rollout notes + - validation plan and manual-validation gaps + - recommended workflow handoffs when needed + +## Guards and Stop Conditions + +- Do not claim DeviceCheck or App Attest proves a device operating system is uncompromised; Apple positions these as risk signals, not absolute fraud prevention. +- Do not pretend the app can validate its own integrity locally. App Attest trust decisions require server-side challenge and verification. +- Do not reuse App Attest challenges or client data blocks. Use unique, single-use server challenges to reduce replay risk. +- Do not reuse one App Attest key across multiple users on the same device. +- Do not discard a key after `serverUnavailable`; retry later with the same key and same `clientDataHash` when Apple documents that behavior. +- Do not mix sandbox and production App Attest keys, receipts, endpoints, or server records. +- Do not store Apple private keys, authentication keys, JWT signing keys, App Attest receipts, challenges, assertions, or device tokens in logs. +- Do not treat DeviceCheck's two bits as user identity, durable account state, or a substitute for server-side authorization. +- Do not hand-edit Xcode project or entitlement state casually; route Xcode-managed changes to `xcode-build-run-workflow`. +- Stop with `blocked` when the task requires Apple Developer account access, server secrets, production rollout approval, or live device evidence that is not available. + +## Fallbacks and Handoffs + +- Recommend `explore-apple-swift-docs` when the real need is direct Apple documentation lookup for DeviceCheck, App Attest, CryptoKit, entitlements, code signing, or platform availability. +- Recommend `xcode-build-run-workflow` when the next step is App ID capability setup, entitlements, provisioning, signing, build, run, simulator, device, or target membership follow-through. +- Recommend `xcode-testing-workflow` when the next step is repeatable XCTest/XCUITest, sandbox/production test matrices, simulator/device checks, or `.xctestplan` setup. +- Recommend `swift-openapi-client-workflow` when the app-to-server request or generated client contract is the primary implementation work. +- Recommend server-side Swift, OpenAPI, RPC, or backend-specific workflows when the server must verify attestation objects, assertions, DeviceCheck tokens, receipts, JWT authentication, counters, public keys, or fraud-risk policy. +- Recommend the broader client auth and app-sync workflow when the task is Keychain storage, Sign in with Apple, `ASWebAuthenticationSession`, token refresh, logout, multi-account state, offline edits, or sync conflict handling. +- Recommend `references/snippets/apple-xcode-project-core.md` when the user needs reusable Xcode-project policy for a repo that will own DeviceCheck capabilities, entitlements, signing, and target membership. + +## Customization + +Use `references/customization-flow.md`. + +`scripts/customization_config.py` exists to preserve the repo-wide customization-file contract, but the first version of this skill defines no runtime-enforced knobs. + +Keep the first release focused on DeviceCheck/App Attest classification, docs grounding, and handoffs. If future iterations add deterministic checks for entitlements, server validation fixtures, or rollout policy, document the knobs before runtime behavior depends on them. + +## References + +### Workflow References + +- `references/devicecheck-device-state.md` +- `references/app-attest-client-flow.md` +- `references/app-attest-server-validation.md` +- `references/entitlements-app-id-and-validation.md` +- `references/customization-flow.md` + +### Support References + +- Recommend `explore-apple-swift-docs` when the user needs current Apple docs before a DeviceCheck or App Attest implementation choice. +- Recommend `xcode-build-run-workflow` when the user needs target, signing, entitlement, provisioning, build, run, or install follow-through. +- Recommend `xcode-testing-workflow` when the user needs repeatable simulator, device, assertion, environment, or server-contract test design. +- Recommend `swift-openapi-client-workflow` when generated app-to-server client work is the main change. +- Recommend `references/snippets/apple-xcode-project-core.md` when the user needs reusable Xcode project guidance for DeviceCheck and App Attest capability work. + +### Script Inventory + +- `scripts/customization_config.py` diff --git a/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/agents/openai.yaml b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/agents/openai.yaml new file mode 100644 index 00000000..bdaf7b6d --- /dev/null +++ b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "DeviceCheck App Attest Workflow" + short_description: "Plan DeviceCheck and App Attest flows" + default_prompt: "Use $devicecheck-app-attest-workflow to design a DeviceCheck or App Attest flow for an Apple-platform app, starting from current Apple docs and keeping client framework use, server challenges, entitlements, rollout constraints, backend validation, and handoffs to $xcode-build-run-workflow, $xcode-testing-workflow, $swift-openapi-client-workflow, or $explore-apple-swift-docs explicit." diff --git a/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/app-attest-client-flow.md b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/app-attest-client-flow.md new file mode 100644 index 00000000..36709f19 --- /dev/null +++ b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/app-attest-client-flow.md @@ -0,0 +1,76 @@ +# App Attest Client Flow + +Use this reference when the request is about `DCAppAttestService`, app-side key lifecycle, challenge hashing, attestation, assertions, or app fallback behavior. + +## Availability + +Start by checking `DCAppAttestService.shared.isSupported`. + +If App Attest is unsupported, the app and server both need a fallback. The fallback can allow access with lower trust, require additional server-side risk checks, or block high-risk actions, but that policy belongs on the server. + +Apple documents that Action, extensible SSO, and watchOS extensions are supported, while other extension types are not supported even if `isSupported` returns true. + +## Key Creation + +- Call `generateKey(completionHandler:)` to generate one App Attest key per user account per device when possible. +- Persist the returned key identifier in durable app storage. +- Do not try to read or export the private key; the framework keeps it protected. +- Do not reuse one key for multiple remote users on the same device. +- Use the same key pair between an App Clip and its corresponding full app when applicable, storing the identifier in a shared container. +- Expect keys to survive normal app updates but not app reinstall, device migration, or restore from backup. + +## Attestation + +The app should ask the server for a unique, single-use challenge before attestation. + +Client flow: + +1. Get a challenge from the server. +2. Hash the challenge with SHA256 to form `clientDataHash`. +3. Call `attestKey(_:clientDataHash:completionHandler:)` with the key ID and hash. +4. Send the attestation object and key ID to the server. +5. Persist the key ID for future assertions after the server accepts the attestation. + +If `attestKey` fails with `serverUnavailable`, retry later using the same key and the same `clientDataHash`. For other key-related failures, discard the key identifier and create a new key when retrying. + +## Assertions + +After successful server verification, the app can generate assertions for sensitive requests. + +Client flow: + +1. Ask the server for a unique, single-use challenge. +2. Build client data that includes the challenge and the request being protected. +3. Hash the client data with SHA256. +4. Call `generateAssertion(_:clientDataHash:completionHandler:)`. +5. Send the assertion object and client data to the server with the protected request. + +Assertions should be used at meaningful risk points, such as premium content, account-sensitive changes, fraud-sensitive redemption, or other server-defined sensitive operations. + +## App-Side Storage + +Store: + +- key ID +- account association needed to select the right key +- attestation state accepted by the server +- environment marker when development and production flows may coexist during testing + +Do not store: + +- private keys +- reusable challenges +- Apple server authentication keys +- raw assertion objects as proof without server verification +- sensitive server risk decisions in app-local state + +## Operator-Facing Errors + +Make errors say what failed and where: + +- App Attest unsupported on this device or extension type. +- App Attest key generation failed before attestation. +- App Attest attestation could not reach Apple; retry later with the same key and challenge hash. +- Server rejected the attestation object for this key ID. +- Server rejected the assertion for this request challenge. +- Stored key ID is missing, stale, or tied to a different account/environment. diff --git a/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/app-attest-server-validation.md b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/app-attest-server-validation.md new file mode 100644 index 00000000..6dbd2693 --- /dev/null +++ b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/app-attest-server-validation.md @@ -0,0 +1,86 @@ +# App Attest Server Validation + +Use this reference when the request crosses into server-side App Attest verification, receipt handling, fraud metrics, or assertion validation. + +## Boundary + +Apple Dev Skills can describe the server contract and validation checklist, but backend implementation belongs to the relevant server-side Swift, OpenAPI, RPC, or backend-specific workflows when code changes are needed. + +The server owns trust. The app collects Apple framework outputs; it does not decide that it is legitimate. + +## Challenge Contract + +- Generate randomized, unique, single-use challenges. +- Associate each challenge with the account, device record, operation, environment, and expiration time. +- Reject expired, missing, reused, or mismatched challenges. +- Include the challenge in attestation and assertion verification. +- Do not let the client choose or replay challenges. + +## Attestation Verification Checklist + +Server verification usually needs to: + +- decode the attestation object as CBOR +- verify the Apple App Attest certificate chain +- verify the Apple-specific attestation statement format +- recompute the nonce from authenticator data and the challenge hash +- verify the certificate extension nonce +- verify that the key ID matches the attested public key +- verify the RP ID hash for the app's App ID +- verify the counter starts at zero +- verify the App Attest environment through `aaguid` +- verify the credential ID +- verify Apple extension fields such as validation category and bundle version when the current Apple docs require them +- store the public key, key ID, receipt, environment, account, device association, and starting counter + +On macOS, Apple documents additional verification details involving the signing identifier and the key access-policy hash. Do not treat iOS-only verification notes as sufficient for macOS. + +## Assertion Verification Checklist + +For each protected request, the server usually needs to: + +- decode the assertion object +- rebuild the client data from the protected request and one-time challenge +- hash the client data +- verify the signature with the stored public key +- verify the RP ID hash +- verify the assertion counter is greater than the previous stored counter +- verify the embedded challenge matches the server-issued challenge +- verify environment, validation category, and bundle version when relevant +- store the updated counter after successful verification +- reject replayed or out-of-order assertions + +## Receipt and Fraud Metric Handling + +The attestation statement includes a receipt that the server can use for App Attest fraud metric requests. + +Server handling should: + +- verify receipts before trusting them +- store one key/receipt pair per user-device-environment association +- keep development and production pairs separate +- use the sandbox App Attest data endpoint for sandbox receipts +- use the production App Attest data endpoint for distributed app receipts +- refresh metrics only after the receipt's not-before date and before expiration +- treat the returned metric as a risk signal, not a single automatic allow/deny rule + +## Common Server Handoffs + +- Use server-side Swift guidance for Vapor, Hummingbird, JWT signing, CBOR/COSE/ASN.1 parsing, route handlers, and persistence models. +- Use OpenAPI or RPC guidance when the app/server challenge, attestation, assertion, or fraud-metric API contract is the main design artifact. +- Use security review workflows when the implementation touches production keys, abuse policy, fraud scoring, or high-impact access control. + +## Logging and Secrets + +Do not log: + +- raw challenges after issuance +- assertion objects +- attestation objects +- receipts +- private server keys +- Apple authentication keys +- generated JWTs +- account identifiers next to raw device integrity artifacts + +Prefer structured logs that say which phase failed, which environment was used, and which high-level verification check failed without exposing the artifact. diff --git a/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/customization-flow.md b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/customization-flow.md new file mode 100644 index 00000000..b975b283 --- /dev/null +++ b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/customization-flow.md @@ -0,0 +1,30 @@ +# DeviceCheck App Attest Workflow Customization Contract + +## Purpose + +Preserve the repo-wide customization-file contract without pretending the first version of `devicecheck-app-attest-workflow` already has runtime-tunable behavior. + +## Knobs + +The first version defines no documented runtime-enforced knobs. + +Keep the skill stable around its docs-first DeviceCheck and App Attest decision model before introducing persistent settings. + +## Runtime Behavior + +- `scripts/customization_config.py` exists so the skill participates cleanly in the shared repo customization surface. +- `devicecheck-app-attest-workflow` currently ignores persisted settings at runtime because no runtime-enforced knobs are documented yet. +- Future runtime knobs should only be added after the skill proves a stable need for deterministic configuration. + +## Update Flow + +1. Inspect current settings with `scripts/customization_config.py effective`. +2. If a real runtime knob is being introduced, update `SKILL.md` and the affected references first. +3. Persist the metadata change with `scripts/customization_config.py apply --input `. +4. Re-run `scripts/customization_config.py effective` and confirm the stored values match the documented knob set. +5. Verify the skill text and any future runtime logic agree on the same contract. + +## Validation + +1. Verify the skill does not claim runtime-tunable behavior that is not actually implemented. +2. Verify future knobs are documented in both `SKILL.md` and this file before runtime behavior depends on them. diff --git a/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/customization.template.yaml b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/customization.template.yaml new file mode 100644 index 00000000..cddd82d1 --- /dev/null +++ b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/customization.template.yaml @@ -0,0 +1,3 @@ +schemaVersion: 1 +isCustomized: false +settings: {} diff --git a/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/devicecheck-device-state.md b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/devicecheck-device-state.md new file mode 100644 index 00000000..9c7cb265 --- /dev/null +++ b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/devicecheck-device-state.md @@ -0,0 +1,47 @@ +# DeviceCheck Device State + +Use this reference when the request is about `DCDevice`, Apple-hosted per-device state, or the DeviceCheck query, update, and validate server endpoints. + +## Decision Boundary + +Use DeviceCheck when a server needs a narrow Apple-backed signal for a device, such as whether a device has already used a promotion or has been flagged by the service's own fraud policy. + +Do not use DeviceCheck as account identity, user authentication, authorization, subscription state, local device fingerprinting, or a replacement for server-side abuse controls. + +## App Responsibilities + +- Import `DeviceCheck`. +- Check `DCDevice.current.isSupported` before calling `generateToken(completionHandler:)`. +- Generate a token only when the server needs to query, update, or validate the two bits. +- Send the token to the server over the app's existing authenticated transport when account context matters. +- Treat token generation errors as concrete operator-facing failures, including whether DeviceCheck is unsupported, token generation failed, or server verification failed. + +## Server Responsibilities + +- Obtain the DeviceCheck authentication key from Apple Developer account setup. +- Generate an ES256 JWT for Apple server API requests. +- Use the development DeviceCheck base URL only for development traffic. +- Use the production DeviceCheck base URL for production traffic. +- Implement query and update semantics for the two bits with clear business meaning. +- Store the meaning, timestamp, and policy attached to each bit in server-side docs or code, because Apple stores only the bit values and reports last-modified dates. +- Decide when a device's bits should be reset, such as account recovery, device resale, fraud review, or promotion policy expiry. + +## Common Shapes + +- Promotion eligibility: one bit records whether a device has used a trial, coupon, or bonus. +- Abuse flag: one bit records whether the service has decided to treat the device as high risk. +- Validation-only flow: the server validates that a token came from the app on an Apple device without changing bit state. + +## Failure Modes + +- DeviceCheck is not available on the device. +- The app lacks a registered App ID or the needed Apple Developer setup. +- The server JWT is malformed, expired, signed with the wrong key, or sent to the wrong environment. +- The server mixes business meanings for the two bits over time. +- The app treats the two bits as a user account property and surprises legitimate users who share, sell, replace, or restore devices. + +## Validation Notes + +- Unit-test server bit-policy mapping separately from Apple HTTP calls. +- Integration-test Apple endpoint calls only with development credentials and development endpoints unless production rollout is explicitly approved. +- Do not log device tokens, JWTs, Apple authentication keys, account identifiers, or raw server responses that include sensitive identifiers. diff --git a/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/entitlements-app-id-and-validation.md b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/entitlements-app-id-and-validation.md new file mode 100644 index 00000000..3962f267 --- /dev/null +++ b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/entitlements-app-id-and-validation.md @@ -0,0 +1,63 @@ +# Entitlements, App ID, and Validation + +Use this reference when the request involves Apple Developer setup, App ID registration, entitlements, signing, environments, rollout, or Xcode validation for DeviceCheck or App Attest. + +## App ID and Capability Setup + +DeviceCheck and App Attest require an app ID registered through Apple Developer account surfaces. Before implementation claims are made, verify the bundle identifier, App ID prefix or Team ID, target platform, and distribution context. + +When the change touches Xcode project state, provisioning, entitlements, target membership, signing certificates, or capabilities, hand the mutation to `xcode-build-run-workflow`. + +## App Attest Environment + +Apple documents separate development/sandbox and production behavior for App Attest: + +- During development, App Attest uses sandbox behavior by default. +- Production behavior can be requested during development with the App Attest environment entitlement set to `production`. +- Distributed apps operate in production mode. +- Sandbox keys and receipts cannot be used in production. +- Production keys and receipts cannot be used in sandbox. +- Sandbox fraud-metric requests use the development App Attest data endpoint. +- Production fraud-metric requests use the production App Attest data endpoint. + +Keep the server's environment records explicit so a sandbox attestation cannot be accepted as production or vice versa. + +## macOS Notes + +Do not assume iOS verification rules are enough for macOS. + +Apple documents macOS-specific App Attest validation details, including use of the signing identifier in the RP ID and verification of the key access-policy hash. A server implementation that supports macOS should have explicit tests and docs for those checks. + +Developer ID, App Store, TestFlight, Enterprise, ad hoc, and development signatures may appear differently in validation category checks. Treat validation-category policy as a server risk decision and keep it documented. + +## Extensions and App Clips + +- App Clips should share the key identifier with the corresponding full app when using the same App Attest key pair. +- Action, extensible SSO, and watchOS extensions are documented as supported for App Attest. +- Other extension types are not supported even if `isSupported` returns true. +- Extension support should be verified in the current Apple docs before implementation. + +## Rollout Planning + +For large existing apps, do not enable App Attest attestation for every user at once. Apple documents gradual onboarding guidance because `attestKey` contacts Apple servers and can encounter rate limits. + +Rollout plans should include: + +- feature flag or server-side cohorting +- retry behavior for Apple server unavailability +- rollback or pullback controls +- unsupported-device fallback policy +- observability for attestation and assertion failure reasons +- separation of sandbox, TestFlight, App Store, Enterprise, and Developer ID metrics + +## Validation Paths + +Use the smallest honest validation: + +- static review for skill guidance and docs-only changes +- Xcode build for entitlement and framework import changes +- app run or device/simulator validation when availability, lifecycle, or extension behavior matters +- server unit tests for challenge expiry, replay rejection, counter updates, environment separation, and policy mapping +- integration tests against Apple development endpoints only when credentials and explicit approval are available + +Report manual-validation gaps plainly when Apple Developer account access, server credentials, physical device evidence, or production rollout approval is unavailable. diff --git a/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/snippets/apple-xcode-project-core.md b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/snippets/apple-xcode-project-core.md new file mode 100644 index 00000000..73d9122c --- /dev/null +++ b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/references/snippets/apple-xcode-project-core.md @@ -0,0 +1,104 @@ +# 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. +- Use Xcode MCP DocumentationSearch or Xcode-local documentation first for Apple-owned SDK, framework, and lifecycle questions; use Dash MCP or Dash HTTP next when installed local package docs or multi-ecosystem docs are a better fit; then use official Apple documentation when local docs are insufficient. +- 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, and call `unload_models` on Gale's live TTS service before the heavy run and `reload_models` after it ends, even when the run fails or is interrupted. +- 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 views as component UI: keep them small, composable, reusable, and easy to scan from top to bottom. +- Prefer straight, top-down data flow with small focused controller classes that own matching state for a view or small view cluster. +- 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. +- 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. +- Prefer `@Query` for view-driven SwiftData fetching that should stay in sync with the model context; use explicit fetches only when the view should not be driven by a live query. +- Prefer environment values for shared context that truly belongs to the surrounding hierarchy, not as a dumping ground for unrelated dependencies. +- 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 `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 plans, project references, build configurations, generation options, and project-level settings in the XcodeGen specs instead of editing the generated `.pbxproj`. +- 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, then per-configuration or per-target configs that include the base 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. +- Do not put secrets in `.xcconfig` files. Use build settings only for non-secret configuration values, 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. +- After changing XcodeGen specs or `.xcconfig` files, 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, or build-setting 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/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/scripts/customization_config.py b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/scripts/customization_config.py new file mode 100755 index 00000000..58ca0aeb --- /dev/null +++ b/plugins/apple-dev-skills/skills/devicecheck-app-attest-workflow/scripts/customization_config.py @@ -0,0 +1,213 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.9" +# dependencies = [ +# "PyYAML>=6.0.2,<7", +# ] +# /// +"""Load and persist per-skill customization state.""" + +from __future__ import annotations + +import argparse +import copy +import os +import re +import sys +from pathlib import Path + +import yaml + +SCHEMA_VERSION = 1 +SKILL_NAME = "devicecheck-app-attest-workflow" +CONFIG_HOME_ENV = "APPLE_DEV_SKILLS_CONFIG_HOME" +DEFAULT_CONFIG_ROOT = "~/.config/gaelic-ghost/apple-dev-skills" +ALLOWED_TOP_LEVEL = {"schemaVersion", "isCustomized", "settings"} + + +def fail(message: str) -> None: + print(f"ERROR: {message}", file=sys.stderr) + raise SystemExit(1) + + +def quote_string(value: str) -> str: + escaped = value.replace("\\", "\\\\").replace('"', '\\"') + return f'"{escaped}"' + + +def encode_scalar(value) -> str: + if isinstance(value, bool): + return "true" if value else "false" + if isinstance(value, int): + return str(value) + if value is None: + return quote_string("") + return quote_string(str(value)) + + +def parse_yaml(path: Path) -> dict: + if not path.exists(): + fail(f"Missing YAML file: {path}") + + try: + loaded = yaml.safe_load(path.read_text(encoding="utf-8")) + except yaml.YAMLError as exc: + fail(f"Invalid YAML in {path}: {exc}") + + if loaded is None: + return {} + if not isinstance(loaded, dict): + fail(f"Top-level YAML document must be a mapping in {path}") + + if isinstance(loaded.get("settings"), dict): + loaded["settings"] = { + key: ("" if value is None else value) for key, value in loaded["settings"].items() + } + + return loaded + + +def validate_config(config: dict, *, allow_partial: bool) -> None: + unknown = set(config.keys()) - ALLOWED_TOP_LEVEL + if unknown: + fail(f"Unknown top-level keys: {', '.join(sorted(unknown))}") + + if not allow_partial: + for required in ("schemaVersion", "isCustomized", "settings"): + if required not in config: + fail(f"Missing required key: {required}") + + if "schemaVersion" in config and config["schemaVersion"] != SCHEMA_VERSION: + fail(f"schemaVersion must be {SCHEMA_VERSION}") + + if "isCustomized" in config and not isinstance(config["isCustomized"], bool): + fail("isCustomized must be boolean") + + if "settings" in config: + if not isinstance(config["settings"], dict): + fail("settings must be a mapping") + for key, value in config["settings"].items(): + if not re.fullmatch(r"[A-Za-z0-9_]+", key): + fail(f"Invalid settings key: {key}") + if isinstance(value, (dict, list)): + fail(f"settings values must be scalar: {key}") + + +def merge_configs(base: dict, overlay: dict) -> dict: + merged = { + "schemaVersion": base.get("schemaVersion", SCHEMA_VERSION), + "isCustomized": base.get("isCustomized", False), + "settings": copy.deepcopy(base.get("settings", {})), + } + + if "schemaVersion" in overlay: + merged["schemaVersion"] = overlay["schemaVersion"] + if "isCustomized" in overlay: + merged["isCustomized"] = overlay["isCustomized"] + if "settings" in overlay: + merged["settings"].update(overlay["settings"]) + + return merged + + +def dump_yaml(config: dict) -> str: + lines = [ + f"schemaVersion: {int(config['schemaVersion'])}", + f"isCustomized: {'true' if config['isCustomized'] else 'false'}", + "settings:", + ] + for key in sorted(config["settings"].keys()): + lines.append(f" {key}: {encode_scalar(config['settings'][key])}") + return "\n".join(lines) + "\n" + + +def template_path() -> Path: + return Path(__file__).resolve().parents[1] / "references" / "customization.template.yaml" + + +def config_root() -> Path: + root = os.environ.get(CONFIG_HOME_ENV, DEFAULT_CONFIG_ROOT) + return Path(root).expanduser() + + +def durable_path() -> Path: + return config_root() / SKILL_NAME / "customization.yaml" + + +def load_template() -> dict: + cfg = parse_yaml(template_path()) + validate_config(cfg, allow_partial=False) + return cfg + + +def load_durable() -> dict: + path = durable_path() + if not path.exists(): + return {} + cfg = parse_yaml(path) + validate_config(cfg, allow_partial=False) + return cfg + + +def cmd_path(_: argparse.Namespace) -> None: + print(durable_path()) + + +def cmd_effective(_: argparse.Namespace) -> None: + effective = merge_configs(load_template(), load_durable()) + validate_config(effective, allow_partial=False) + print(dump_yaml(effective), end="") + + +def cmd_apply(args: argparse.Namespace) -> None: + template = load_template() + current = merge_configs(template, load_durable()) + incoming = parse_yaml(Path(args.input)) + validate_config(incoming, allow_partial=True) + + updated = merge_configs(current, incoming) + updated["schemaVersion"] = SCHEMA_VERSION + updated["isCustomized"] = True + validate_config(updated, allow_partial=False) + + target = durable_path() + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(dump_yaml(updated), encoding="utf-8") + print(target) + + +def cmd_reset(_: argparse.Namespace) -> None: + target = durable_path() + if target.exists(): + target.unlink() + print(target) + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="Manage per-skill customization config") + subparsers = parser.add_subparsers(dest="command", required=True) + + parser_path = subparsers.add_parser("path", help="Print durable config path") + parser_path.set_defaults(func=cmd_path) + + parser_effective = subparsers.add_parser("effective", help="Print merged effective config") + parser_effective.set_defaults(func=cmd_effective) + + parser_apply = subparsers.add_parser("apply", help="Apply and persist config overrides") + parser_apply.add_argument("--input", required=True, help="Path to YAML overrides") + parser_apply.set_defaults(func=cmd_apply) + + parser_reset = subparsers.add_parser("reset", help="Delete durable config for this skill") + parser_reset.set_defaults(func=cmd_reset) + + return parser + + +def main() -> None: + parser = build_parser() + args = parser.parse_args() + args.func(args) + + +if __name__ == "__main__": + main() 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 6a9f7730..72bcf858 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, 28) - self.assertEqual(script_count, 28) + self.assertEqual(template_count, 29) + self.assertEqual(script_count, 29) 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 new file mode 100644 index 00000000..917c2941 --- /dev/null +++ b/plugins/apple-dev-skills/tests/test_devicecheck_app_attest_workflow.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +class DeviceCheckAppAttestWorkflowTests(unittest.TestCase): + def read(self, relative_path: str) -> str: + return (ROOT / relative_path).read_text(encoding="utf-8") + + def test_skill_separates_devicecheck_and_app_attest_paths(self) -> None: + skill_text = self.read("skills/devicecheck-app-attest-workflow/SKILL.md") + device_text = self.read("skills/devicecheck-app-attest-workflow/references/devicecheck-device-state.md") + client_text = self.read("skills/devicecheck-app-attest-workflow/references/app-attest-client-flow.md") + + self.assertIn("DeviceCheck two-bit state with `DCDevice`", skill_text) + self.assertIn("App Attest app-instance integrity with `DCAppAttestService`", skill_text) + self.assertIn("query, update, or validate the two bits", device_text) + self.assertIn("Do not use DeviceCheck as account identity", device_text) + self.assertIn("generateKey(completionHandler:)", client_text) + self.assertIn("attestKey(_:clientDataHash:completionHandler:)", client_text) + self.assertIn("generateAssertion(_:clientDataHash:completionHandler:)", client_text) + + def test_skill_requires_docs_gate_and_supported_apple_behavior(self) -> None: + skill_text = self.read("skills/devicecheck-app-attest-workflow/SKILL.md") + client_text = self.read("skills/devicecheck-app-attest-workflow/references/app-attest-client-flow.md") + entitlement_text = self.read("skills/devicecheck-app-attest-workflow/references/entitlements-app-id-and-validation.md") + + self.assertIn("Apply the Apple docs gate", skill_text) + self.assertIn("state the documented Apple behavior being relied on", skill_text) + self.assertIn("Action, extensible SSO, and watchOS extensions", client_text) + self.assertIn("sandbox and production", entitlement_text) + self.assertIn("macOS-specific App Attest validation", entitlement_text) + + def test_server_validation_stays_a_handoff_not_app_local_trust(self) -> None: + skill_text = self.read("skills/devicecheck-app-attest-workflow/SKILL.md") + server_text = self.read("skills/devicecheck-app-attest-workflow/references/app-attest-server-validation.md") + + self.assertIn("Do not pretend the app can validate its own integrity locally", skill_text) + self.assertIn("The server owns trust", server_text) + self.assertIn("decode the attestation object as CBOR", server_text) + self.assertIn("verify the assertion counter is greater than the previous stored counter", server_text) + self.assertIn("server-side Swift, OpenAPI, RPC, or backend-specific workflows", server_text) + + def test_skill_handoffs_and_metadata_are_explicit(self) -> None: + skill_text = self.read("skills/devicecheck-app-attest-workflow/SKILL.md") + prompt_text = self.read("skills/devicecheck-app-attest-workflow/agents/openai.yaml") + + self.assertIn("Recommend `explore-apple-swift-docs`", skill_text) + self.assertIn("Recommend `xcode-build-run-workflow`", skill_text) + self.assertIn("Recommend `xcode-testing-workflow`", skill_text) + self.assertIn("Recommend `swift-openapi-client-workflow`", skill_text) + self.assertIn("broader client auth and app-sync workflow", skill_text) + self.assertIn("references/snippets/apple-xcode-project-core.md", skill_text) + self.assertIn("$devicecheck-app-attest-workflow", prompt_text) + self.assertIn("$xcode-build-run-workflow", prompt_text) + self.assertIn("$xcode-testing-workflow", prompt_text) + self.assertIn("$swift-openapi-client-workflow", prompt_text) + self.assertIn("$explore-apple-swift-docs", prompt_text) + + def test_plugin_inventory_includes_devicecheck_workflow(self) -> None: + readme = self.read("README.md") + plugin = self.read(".codex-plugin/plugin.json") + validator = self.read(".github/scripts/validate_repo_docs.sh") + roadmap = self.read("ROADMAP.md") + + self.assertIn("devicecheck-app-attest-workflow", readme) + self.assertIn("DeviceCheck", plugin) + self.assertIn("App Attest", plugin) + self.assertIn("./skills/devicecheck-app-attest-workflow/SKILL.md", validator) + self.assertIn("Expected exactly 29 active skills", validator) + self.assertIn("Milestone 53: DeviceCheck and App Attest Workflow - Completed", roadmap) + + +if __name__ == "__main__": + unittest.main() From 67e9c9e130ce117cf048be7669cb07a63c9c63ba Mon Sep 17 00:00:00 2001 From: Gale W Date: Thu, 2 Jul 2026 10:15:35 -0400 Subject: [PATCH 3/3] docs: document Xcode toolchain selection --- ROADMAP.md | 3 +- docs/maintainers/agent-portability-options.md | 10 ++-- .../devicecheck-app-attest-skill-plan.md | 16 +++--- .../xcode-27-agentic-tooling-plan.md | 6 +-- .../xcode-plugin-install-support-plan.md | 2 +- plugins/apple-dev-skills/AGENTS.md | 2 +- .../icon-composer-app-icon-workflow/SKILL.md | 10 ++-- .../references/toolchain-management.md | 19 ++++++- .../references/toolchain-management.md | 19 ++++++- .../SKILL.md | 5 +- .../mcpbridge-and-external-agents.md | 2 +- .../references/setup-and-agent-surfaces.md | 4 +- .../references/source-evidence.md | 26 +++++++++- .../references/toolchain-management.md | 19 ++++++- ...test_xcode_coding_intelligence_workflow.py | 16 ++++++ ...test_xcode_toolchain_selection_guidance.py | 49 +++++++++++++++++++ 16 files changed, 172 insertions(+), 36 deletions(-) create mode 100644 plugins/apple-dev-skills/tests/test_xcode_toolchain_selection_guidance.py diff --git a/ROADMAP.md b/ROADMAP.md index 8e4c34a4..9a31dce9 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -328,6 +328,7 @@ In Progress - [ ] Add a dedicated Xcode 27 beta LLDB MCP workflow skill after `xcrun lldb-mcp` startup is validated. Xcode 27 Beta 2 exposes `lldb-mcp`, and Apple Dev Skills now carries an experimental `xcode_lldb` MCP config entry, but local `--help` invocation failed on 2026-06-26 with a missing `lib_CompilerSwiftIDEUtils.dylib` rpath load. - [ ] Add `apple-dev-skills:xcode-agent-plugin-workflow` now that the live Xcode 27 beta plug-in import paths are verified through installed Codex state, local folder import, and public Git URL import. - [x] Refresh `xcode-build-run-workflow` and `xcode-testing-workflow` so setup and permissions route to the new coding-intelligence skill while build/test execution stays owned by the existing skills. +- [x] Document Xcode command-line toolchain selection for stable and beta Xcode installs, including command-scoped `DEVELOPER_DIR`, explicit global `xcode-select --switch`, restore steps, and current system-wide beta app paths. - [ ] Refresh SwiftUI guidance for Xcode 27 APIs such as `ContentBuilder`, `@State` macro behavior, reorderable containers, generalized swipe actions, toolbar overflow, URL-backed documents, AsyncImage request/session APIs, and gesture input kinds. - [ ] Refresh AppKit, UIKit, and Icon Composer guidance for the Xcode 27 beta changes recorded in the plan. @@ -501,7 +502,7 @@ Planned - [ ] Add common skill constraint checks for Codex and OpenCode first, then include Zed as an informational follow-up target. - [ ] Add a dry-run OpenCode skills export plan for `.agents/skills` and `.opencode/skills`, starting with project-local fixtures and temporary homes. - [ ] Evaluate OpenCode adapters for `.opencode/skills`, `opencode.json`, MCP config, permissions, and TypeScript plugin modules. -- [ ] Evaluate Xcode 27 beta adapters using `DEVELOPER_DIR=/Users/galew/Applications/Betas/Xcode-beta.app/Contents/Developer`, including Xcode-launched Codex configuration, MCP bridge behavior, and Xcode plug-in imports through the official Settings UI. Initial live beta bridge and plug-in import evidence was captured on 2026-06-23. +- [ ] Evaluate Xcode 27 beta adapters using command-scoped `DEVELOPER_DIR` for the intended system-wide beta app, including Xcode-launched Codex configuration, MCP bridge behavior, and Xcode plug-in imports through the official Settings UI. Initial live beta bridge and plug-in import evidence was captured on 2026-06-23. - [ ] Add a Socket-to-Xcode install support assessment that classifies each child plugin across Xcode-launched Codex, Xcode internal plug-ins, and external agents using Xcode MCP. - [ ] Add disposable Xcode import fixture generation for skill-only, skill-plus-MCP, and hook-recognition probes. - [ ] Capture a public Socket Git URL import matrix from Xcode Beta before claiming user-facing Xcode install support. diff --git a/docs/maintainers/agent-portability-options.md b/docs/maintainers/agent-portability-options.md index 21849347..d0f132d8 100644 --- a/docs/maintainers/agent-portability-options.md +++ b/docs/maintainers/agent-portability-options.md @@ -22,10 +22,10 @@ Start with Xcode 27 beta and OpenCode. Those are the two locally installed targets available for immediate smoke tests on Gale's machine: -- Xcode 27 beta: `/Users/galew/Applications/Betas/Xcode-beta.app`, verified with `DEVELOPER_DIR=/Users/galew/Applications/Betas/Xcode-beta.app/Contents/Developer xcodebuild -version` as Xcode 27.0 build 27A5194q. +- Xcode 27 beta: `/Applications/Xcode-beta.app`, verified on 2026-07-02 with `DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer xcodebuild -version` as Xcode 27.0 build 27A5209h. - Xcode 27 beta live bridge: verified on 2026-06-23 with the beta app open and selected through `MCP_XCODE_PID`; `run-agent --dry-run codex` resolved the beta-scoped Codex runtime and Xcode-specific `CODEX_HOME`. A direct `codex skills export` attempt through that runtime failed in this beta with `unrecognized subcommand 'export'`, so do not rely on that as an install or export path. - Xcode 27 beta plug-in import: verified on 2026-06-23 through the Xcode Beta Settings UI. `Import from Codex`, `Add from file`, and `Add from URL` all recognized agentic plug-in payloads; `Add from URL` accepted `https://github.com/gaelic-ghost/socket.git` and enumerated Socket child plug-ins before import. -- Active command-line Xcode: `/Applications/Xcode.app`, currently Xcode 26.5 build 17F42 through the default `xcodebuild -version`. +- Active command-line Xcode: `/Applications/Xcode-beta.app/Contents/Developer`, currently Xcode 27.0 build 27A5209h through the default `xcodebuild -version`. - OpenCode CLI: `/opt/homebrew/bin/opencode`, verified as 1.17.9. - OpenCode Desktop: `/Applications/OpenCode.app`, present locally. @@ -63,10 +63,10 @@ Xcode support needs three different answers: Local validation target: -- Use `DEVELOPER_DIR=/Users/galew/Applications/Betas/Xcode-beta.app/Contents/Developer` for Xcode 27 beta checks until the active command-line developer directory is intentionally changed. -- Open `/Users/galew/Applications/Betas/Xcode-beta.app` for live beta UI, MCP, agent, and plug-in checks instead of treating a closed app as a blocker. +- Prefer command-scoped `DEVELOPER_DIR` for Xcode beta checks when the task should not change the global command-line developer directory. Current system-wide beta candidates are `/Applications/Xcode-beta.app` and `/Applications/Betas/Xcode-beta.app`. +- Open the intended stable or beta Xcode app for live UI, MCP, agent, and plug-in checks instead of treating a closed app as a blocker. - Use `MCP_XCODE_PID` when stable and beta Xcode processes could both exist or when the bridge must target the beta process explicitly. -- Keep the default Xcode 26.5 path untouched unless a task explicitly needs `xcode-select` changes. +- Change global `xcode-select` only when the task explicitly needs the default command-line tools selection to change. Record the previous `xcode-select -p` value, switch with `sudo xcode-select --switch `, verify, and restore the previous path when the global check is finished. Practical Socket implication: diff --git a/docs/maintainers/devicecheck-app-attest-skill-plan.md b/docs/maintainers/devicecheck-app-attest-skill-plan.md index 0e6fb88c..d6a83796 100644 --- a/docs/maintainers/devicecheck-app-attest-skill-plan.md +++ b/docs/maintainers/devicecheck-app-attest-skill-plan.md @@ -1,6 +1,6 @@ -# DeviceCheck and App Attest Skill Plan +# DeviceCheck and App Attest Skill Record -This plan captures a candidate Apple Dev Skills expansion for the DeviceCheck framework, including per-device DeviceCheck state and App Attest app-instance validation. +This record captures the shipped Apple Dev Skills expansion for the DeviceCheck framework, including per-device DeviceCheck state and App Attest app-instance validation. ## Status @@ -31,13 +31,13 @@ App Attest has important rollout and environment constraints: - App Attest does not prove that a device operating system is uncompromised; it supplies one signal for a broader fraud-risk decision. - On macOS, App Attest verification has macOS-specific signing identifier and key access-policy checks. -## Proposed Skill +## Implemented Skill ### `devicecheck-app-attest-workflow` Use for DeviceCheck and App Attest decisions in Apple-platform apps, including `DCDevice`, per-device two-bit state, `DCAppAttestService`, App Attest key lifecycle, server challenge design, attestation and assertion request shapes, app IDs, entitlements, sandbox versus production environments, rollout/rate-limit planning, and client/server handoffs. -This skill should help an agent: +This skill helps an agent: - classify whether the request is DeviceCheck two-bit device state, App Attest app-instance integrity, or a broader auth/session/sync concern - apply the Apple docs gate before making current framework, entitlement, platform, or server-endpoint claims @@ -49,11 +49,11 @@ This skill should help an agent: - route generated client APIs to `swift-openapi-client-workflow` - route backend validation implementation to the relevant server-side Swift or API-contract workflow when available -## Skill Shape +## Shipped Skill Shape -The first version should be guidance and routing, not a deterministic validator. App Attest server verification includes CBOR, COSE, ASN.1, certificate-chain, receipt, environment, signing-category, and counter checks, which are too stack-specific for a tiny first slice. +The shipped first version is guidance and routing, not a deterministic validator. App Attest server verification includes CBOR, COSE, ASN.1, certificate-chain, receipt, environment, signing-category, and counter checks, which are too stack-specific for a tiny first slice. -Recommended first payload: +Shipped first payload: - `SKILL.md` with the core workflow, docs gate, classification, handoffs, and guardrails. - `agents/openai.yaml` metadata generated from the skill body. @@ -84,7 +84,7 @@ Avoid scripts in the first slice unless a concrete backend stack needs one. If a - [x] Run `uv run pytest` from `plugins/apple-dev-skills` when tests change. - [x] Run `uv run scripts/validate_socket_metadata.py` from the Socket root after metadata changes. -## Open Questions +## Future Questions - The first implementation uses `devicecheck-app-attest-workflow`; a broader `apple-app-integrity-workflow` can still be considered later if another Apple integrity signal needs a shared owner. - Should server-validation guidance stay purely checklist-based at first, or should the initial skill include stack-specific examples for Swift server apps? diff --git a/docs/maintainers/xcode-27-agentic-tooling-plan.md b/docs/maintainers/xcode-27-agentic-tooling-plan.md index ab36046f..b01f1dee 100644 --- a/docs/maintainers/xcode-27-agentic-tooling-plan.md +++ b/docs/maintainers/xcode-27-agentic-tooling-plan.md @@ -43,9 +43,9 @@ Refresh checked on 2026-06-22: Live beta probe checked on 2026-06-23: -- Xcode 27 beta was opened from `/Users/galew/Applications/Betas/Xcode-beta.app`. -- `DEVELOPER_DIR=/Users/galew/Applications/Betas/Xcode-beta.app/Contents/Developer MCP_XCODE_PID=59740 xcrun mcpbridge run-agent --dry-run codex` resolved Xcode's beta-scoped Codex executable and `CODEX_HOME`. -- `DEVELOPER_DIR=/Users/galew/Applications/Betas/Xcode-beta.app/Contents/Developer MCP_XCODE_PID=59740 xcrun mcpbridge run-agent codex skills export --output-dir /private/tmp/socket-xcode-plugin-fixture/after-file-import-skills --replace-existing` launched Xcode's beta-scoped Codex runtime, but that runtime reported `unrecognized subcommand 'export'`. Treat `skills export` as unusable from this Codex runtime until a later beta proves otherwise. +- Xcode 27 beta was opened from the then-installed beta app path. +- The matching beta `DEVELOPER_DIR` plus `MCP_XCODE_PID=59740 xcrun mcpbridge run-agent --dry-run codex` resolved Xcode's beta-scoped Codex executable and `CODEX_HOME`. +- The matching beta `DEVELOPER_DIR` plus `MCP_XCODE_PID=59740 xcrun mcpbridge run-agent codex skills export --output-dir /private/tmp/socket-xcode-plugin-fixture/after-file-import-skills --replace-existing` launched Xcode's beta-scoped Codex runtime, but that runtime reported `unrecognized subcommand 'export'`. Treat `skills export` as unusable from this Codex runtime until a later beta proves otherwise. - Xcode Beta Settings > Intelligence > Plug-ins was inspected through the official UI. The Add Plug-in sheet exposed `Import from Claude Code`, `Import from Codex`, `Add from file`, and `Add from URL`. - `Import from Codex` imported the installed `apple-dev-skills` plugin as `6 Skills - Hooks`. - `Add from file` imported a harmless fixture folder containing `.codex-plugin/plugin.json`, `skills//SKILL.md`, and `.mcp.json` as `1 Skill - 1 MCP Server`. diff --git a/docs/maintainers/xcode-plugin-install-support-plan.md b/docs/maintainers/xcode-plugin-install-support-plan.md index c190b7b5..84e94c17 100644 --- a/docs/maintainers/xcode-plugin-install-support-plan.md +++ b/docs/maintainers/xcode-plugin-install-support-plan.md @@ -44,7 +44,7 @@ Local probe results: ## Non-Goals - Do not build a separate custom Xcode installer before the official UI path is exhausted. -- Do not change `xcode-select` globally. +- Do not change `xcode-select` globally unless the task explicitly requires a system-wide default command-line tools switch. Prefer command-scoped `DEVELOPER_DIR` for beta checks. - Do not rewrite Socket as an aggregate non-Codex plugin bundle. - Do not claim hook execution, MCP server execution, app config, or custom-agent behavior works in Xcode until runtime probes verify those surfaces. - Do not treat Xcode-generated files as Socket source of truth. diff --git a/plugins/apple-dev-skills/AGENTS.md b/plugins/apple-dev-skills/AGENTS.md index 777873ef..4c1b3420 100644 --- a/plugins/apple-dev-skills/AGENTS.md +++ b/plugins/apple-dev-skills/AGENTS.md @@ -19,7 +19,7 @@ This file is the Apple Dev Skills child-repo override for work done from `socket - If no relevant Apple documentation can be found, say that explicitly before proceeding. - Keep `explore-apple-swift-docs` as the canonical docs-routing surface instead of re-embedding broad docs-source selection logic into execution skills. - When the task depends on a local Apple developer app or utility, verify whether the needed app is running and open it when that is the normal way to inspect or use the surface. This includes stable or beta Xcode, Icon Composer, Instruments, SF Symbols, Simulator, Accessibility Inspector, Console, Audio MIDI Setup, and related Apple developer utilities. Do not turn an unopened local app into a research blocker; launch the relevant app, then verify the window, project, document, or tool state. Ask first only when opening the app would be disruptive, destructive, require signing in, or conflict with a user-stated constraint. -- For Xcode beta work on Gale's MacBook, prefer `DEVELOPER_DIR=/Users/galew/Applications/Betas/Xcode-beta.app/Contents/Developer` for command-line checks and open `/Users/galew/Applications/Betas/Xcode-beta.app` when Xcode 27 beta UI, MCP, or agent behavior needs a live app. Do not change global `xcode-select` unless Gale explicitly asks. +- For Xcode beta work on Gale's MacBook, prefer command-scoped `DEVELOPER_DIR` for checks and use system-wide beta app candidates such as `/Applications/Xcode-beta.app` and `/Applications/Betas/Xcode-beta.app`. Open the intended beta app when Xcode beta UI, MCP, or agent behavior needs a live app. Change global `xcode-select` only when Gale explicitly asks for the default command-line tools version to change, and record the previous `xcode-select -p` value before switching. - Prefer framework-provided behavior over custom wrappers, coordinators, glue, or renaming layers unless a concrete constraint requires them. - For AVFoundation, AVFAudio, Core Media, Core Audio, Audio Toolbox, and related Apple media work, strictly prefer Apple and Swift media types unless they are unsuitable for the concrete app, package, test, wire, persistence, or cross-platform boundary. Preserve framework types such as `CMTime`, `CMSampleBuffer`, `CMFormatDescription`, `AVAudioFormat`, `AudioStreamBasicDescription`, and `OSStatus` until the conversion boundary, information loss, and reason for the escape hatch are explicit. - For Xcode app repos, tracked `.pbxproj` changes are critical project state when produced by Xcode, XcodeGen, or another project-aware workflow. diff --git a/plugins/apple-dev-skills/skills/icon-composer-app-icon-workflow/SKILL.md b/plugins/apple-dev-skills/skills/icon-composer-app-icon-workflow/SKILL.md index a3027892..ccb698f7 100644 --- a/plugins/apple-dev-skills/skills/icon-composer-app-icon-workflow/SKILL.md +++ b/plugins/apple-dev-skills/skills/icon-composer-app-icon-workflow/SKILL.md @@ -50,14 +50,16 @@ Before a live workflow, inspect the Mac and report what is available: 1. Locate Icon Composer. Common stable path: `/Applications/Xcode.app/Contents/Applications/Icon Composer.app` -2. Check the beta Xcode app path as needed: - `/Users/galew/Applications/Betas/Xcode-beta.app/Contents/Applications/Icon Composer.app` +2. Check beta Xcode app paths as needed: + `/Applications/Xcode-beta.app/Contents/Applications/Icon Composer.app` + `/Applications/Betas/Xcode-beta.app/Contents/Applications/Icon Composer.app` 3. Verify the app is present before promising GUI guidance. 4. Open Icon Composer when the task needs live GUI inspection, document editing, platform preview, or behavior that only the app can show. Do not report that Icon Composer behavior is unverifiable merely because the app was not already open. 5. Locate `ictool`. Common stable path: `/Applications/Xcode.app/Contents/Applications/Icon Composer.app/Contents/Executables/ictool` -6. Check the beta `ictool` path as needed: - `/Users/galew/Applications/Betas/Xcode-beta.app/Contents/Applications/Icon Composer.app/Contents/Executables/ictool` +6. Check beta `ictool` paths as needed: + `/Applications/Xcode-beta.app/Contents/Applications/Icon Composer.app/Contents/Executables/ictool` + `/Applications/Betas/Xcode-beta.app/Contents/Applications/Icon Composer.app/Contents/Executables/ictool` 7. Run `ictool --help` or `ictool --version` when preview export is part of the task. 8. Identify the target app project shape before promising Xcode integration. diff --git a/plugins/apple-dev-skills/skills/xcode-app-project-workflow/references/toolchain-management.md b/plugins/apple-dev-skills/skills/xcode-app-project-workflow/references/toolchain-management.md index ae395557..cc3664cf 100644 --- a/plugins/apple-dev-skills/skills/xcode-app-project-workflow/references/toolchain-management.md +++ b/plugins/apple-dev-skills/skills/xcode-app-project-workflow/references/toolchain-management.md @@ -11,12 +11,23 @@ - `xcodebuild -version` - `xcode-select -p` - `xcrun --find swift` +- `xcrun --find xcodebuild` - `xcodebuild -showComponent metalToolchain` ## Official Xcode and CLT actions -- Select active developer directory: - - `xcode-select --switch ` +- Select a toolchain for one command: + - `DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer xcodebuild -version` + - `DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer xcodebuild -version` + - `DEVELOPER_DIR=/Applications/Betas/Xcode-beta.app/Contents/Developer xcodebuild -version` +- Select the system-wide active developer directory only when the user explicitly wants the default CLI tools to change: + - record the current value first with `xcode-select -p` + - switch to stable Xcode with `sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer` + - switch to a beta Xcode with `sudo xcode-select --switch /Applications/Xcode-beta.app/Contents/Developer` or `sudo xcode-select --switch /Applications/Betas/Xcode-beta.app/Contents/Developer` + - verify with `xcode-select -p`, `xcodebuild -version`, and `xcrun --find swift` + - restore the previous path with another `sudo xcode-select --switch ` when the global beta test is finished +- Reset default command line tools path: + - `sudo xcode-select --reset` - Install/repair command line tools (interactive on macOS): - `xcode-select --install` @@ -24,6 +35,10 @@ - Prefer explicit output of versions and selected developer dir before diagnosing build/test failures. - Keep fallback commands deterministic and project-local. +- Prefer per-command `DEVELOPER_DIR` when checking a beta, reproducing a toolchain-specific issue, or avoiding changes that affect other shells, editors, CI helpers, and agents on the same Mac. +- Use `xcode-select --switch` when the task is intentionally about changing the default command-line tools selection. `xcode-select` controls tools discovered through `xcrun`, `xcodebuild`, and BSD development commands such as `cc` and `make`. +- Treat `/Applications/Xcode.app` as the usual stable Xcode path. For beta Xcode installs on Gale's MacBook, check system-wide candidates such as `/Applications/Xcode-beta.app` and `/Applications/Betas/Xcode-beta.app` instead of the older user-local `~/Applications/Betas` location. +- Do not use `xcode-select --install` as an Xcode app switch; it opens the interactive Command Line Tools installer. - When a Swift package build appears to depend on Xcode-managed assets or components, verify the active Xcode toolchain before defaulting to `swift build`. - `xcodebuild` may expose Apple-managed toolchain paths, including components like the Metal toolchain, that do not show up the same way through plain SwiftPM invocation. - When Metal shader compilation or packaged `.metallib` validation matters, verify the active Xcode component state and prefer explicit `xcodebuild` validation over assuming SwiftPM alone covers the Apple-managed build path. diff --git a/plugins/apple-dev-skills/skills/xcode-build-run-workflow/references/toolchain-management.md b/plugins/apple-dev-skills/skills/xcode-build-run-workflow/references/toolchain-management.md index ae395557..cc3664cf 100644 --- a/plugins/apple-dev-skills/skills/xcode-build-run-workflow/references/toolchain-management.md +++ b/plugins/apple-dev-skills/skills/xcode-build-run-workflow/references/toolchain-management.md @@ -11,12 +11,23 @@ - `xcodebuild -version` - `xcode-select -p` - `xcrun --find swift` +- `xcrun --find xcodebuild` - `xcodebuild -showComponent metalToolchain` ## Official Xcode and CLT actions -- Select active developer directory: - - `xcode-select --switch ` +- Select a toolchain for one command: + - `DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer xcodebuild -version` + - `DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer xcodebuild -version` + - `DEVELOPER_DIR=/Applications/Betas/Xcode-beta.app/Contents/Developer xcodebuild -version` +- Select the system-wide active developer directory only when the user explicitly wants the default CLI tools to change: + - record the current value first with `xcode-select -p` + - switch to stable Xcode with `sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer` + - switch to a beta Xcode with `sudo xcode-select --switch /Applications/Xcode-beta.app/Contents/Developer` or `sudo xcode-select --switch /Applications/Betas/Xcode-beta.app/Contents/Developer` + - verify with `xcode-select -p`, `xcodebuild -version`, and `xcrun --find swift` + - restore the previous path with another `sudo xcode-select --switch ` when the global beta test is finished +- Reset default command line tools path: + - `sudo xcode-select --reset` - Install/repair command line tools (interactive on macOS): - `xcode-select --install` @@ -24,6 +35,10 @@ - Prefer explicit output of versions and selected developer dir before diagnosing build/test failures. - Keep fallback commands deterministic and project-local. +- Prefer per-command `DEVELOPER_DIR` when checking a beta, reproducing a toolchain-specific issue, or avoiding changes that affect other shells, editors, CI helpers, and agents on the same Mac. +- Use `xcode-select --switch` when the task is intentionally about changing the default command-line tools selection. `xcode-select` controls tools discovered through `xcrun`, `xcodebuild`, and BSD development commands such as `cc` and `make`. +- Treat `/Applications/Xcode.app` as the usual stable Xcode path. For beta Xcode installs on Gale's MacBook, check system-wide candidates such as `/Applications/Xcode-beta.app` and `/Applications/Betas/Xcode-beta.app` instead of the older user-local `~/Applications/Betas` location. +- Do not use `xcode-select --install` as an Xcode app switch; it opens the interactive Command Line Tools installer. - When a Swift package build appears to depend on Xcode-managed assets or components, verify the active Xcode toolchain before defaulting to `swift build`. - `xcodebuild` may expose Apple-managed toolchain paths, including components like the Metal toolchain, that do not show up the same way through plain SwiftPM invocation. - When Metal shader compilation or packaged `.metallib` validation matters, verify the active Xcode component state and prefer explicit `xcodebuild` validation over assuming SwiftPM alone covers the Apple-managed build path. diff --git a/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/SKILL.md b/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/SKILL.md index 3eeb2962..c7698506 100644 --- a/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/SKILL.md +++ b/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/SKILL.md @@ -51,8 +51,9 @@ Beta-specific note: Xcode 27 claims in this skill were checked against Apple dev 4. Plan setup: - verify the target Xcode version and whether the relevant behavior is stable, beta, or local-only - check whether the intended Xcode app is running and open it when needed for project context, MCP bridge connection, agent settings, or UI/plugin inspection - - for Gale's Xcode 27 beta checks, prefer `DEVELOPER_DIR=/Users/galew/Applications/Betas/Xcode-beta.app/Contents/Developer` and open `/Users/galew/Applications/Betas/Xcode-beta.app` when the beta UI or live bridge state is required - - do not change global `xcode-select` unless the user explicitly asks for that system-wide switch + - for Gale's Xcode beta checks, prefer command-scoped `DEVELOPER_DIR` using system-wide beta candidates such as `/Applications/Xcode-beta.app/Contents/Developer` or `/Applications/Betas/Xcode-beta.app/Contents/Developer` + - open the intended beta app when the beta UI or live bridge state is required + - change global `xcode-select` only when the user explicitly asks for that system-wide default CLI tools switch, and record the previous `xcode-select -p` value before switching - verify the project is open in Xcode before expecting Xcode MCP tools to work - verify external-agent access is enabled before configuring an external MCP client - use `xcrun mcpbridge` as the Xcode-provided STDIO bridge for external MCP clients diff --git a/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/references/mcpbridge-and-external-agents.md b/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/references/mcpbridge-and-external-agents.md index 60adda10..0513020d 100644 --- a/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/references/mcpbridge-and-external-agents.md +++ b/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/references/mcpbridge-and-external-agents.md @@ -59,7 +59,7 @@ Before expecting Xcode tools to work through an external agent: - The requested tool permission must be allowed by Xcode and by the external client. - Plug-in import probes should use a harmless fixture or a trusted Git URL first, and should stop before importing additional plug-ins unless the user asked to mutate Xcode state. -Do not treat a non-running Xcode instance as a final blocker by itself. If the task needs Xcode's live project context, MCP bridge, Intelligence settings, or plug-in UI, open the intended Xcode app and then retry the check. For Gale's Xcode 27 beta work, open `/Users/galew/Applications/Betas/Xcode-beta.app` and use `DEVELOPER_DIR=/Users/galew/Applications/Betas/Xcode-beta.app/Contents/Developer` for matching command-line checks. Use stable `/Applications/Xcode.app` when the task targets stable Xcode. Ask first only when opening Xcode would be disruptive, would require signing in, would alter global developer-directory selection, or conflicts with a user-stated constraint. +Do not treat a non-running Xcode instance as a final blocker by itself. If the task needs Xcode's live project context, MCP bridge, Intelligence settings, or plug-in UI, open the intended Xcode app and then retry the check. For Gale's Xcode beta work, check system-wide beta candidates such as `/Applications/Xcode-beta.app` and `/Applications/Betas/Xcode-beta.app`, and use matching command-scoped `DEVELOPER_DIR` values for command-line checks. Use stable `/Applications/Xcode.app` when the task targets stable Xcode. Ask first only when opening Xcode would be disruptive, would require signing in, would alter global developer-directory selection, or conflicts with a user-stated constraint. ## Failure Language diff --git a/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/references/setup-and-agent-surfaces.md b/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/references/setup-and-agent-surfaces.md index 8f969a0d..999fef48 100644 --- a/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/references/setup-and-agent-surfaces.md +++ b/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/references/setup-and-agent-surfaces.md @@ -32,9 +32,9 @@ As of 2026-06-22, Apple's Xcode 27 pages and WWDC26 transcripts describe: Treat these as beta-era Xcode 27 claims until the installed Xcode and current Apple docs confirm the behavior for the target machine. -Local beta tool check on 2026-06-22 verified Xcode 27.0 beta build 27A5194q at `/Users/galew/Applications/Betas/Xcode-beta.app`. The local check verified `xcodebuild -version`, `xcrun --find mcpbridge`, and `xcrun mcpbridge --help`; it did not verify Xcode UI settings, project-session permissions, or agent execution inside a running Xcode session. +Local beta tool check on 2026-06-22 verified Xcode 27.0 beta build 27A5194q at the then-installed beta app path. The local check verified `xcodebuild -version`, `xcrun --find mcpbridge`, and `xcrun mcpbridge --help`; it did not verify Xcode UI settings, project-session permissions, or agent execution inside a running Xcode session. -When a claim depends on live Xcode UI, an open project, MCP connection state, agent settings, or plug-in import behavior, open the intended Xcode app and inspect the live state. For Gale's Xcode 27 beta work, use `/Users/galew/Applications/Betas/Xcode-beta.app`; for stable work, use `/Applications/Xcode.app`. Use explicit `DEVELOPER_DIR` for matching command-line checks instead of changing global `xcode-select` unless Gale asks for a global switch. +When a claim depends on live Xcode UI, an open project, MCP connection state, agent settings, or plug-in import behavior, open the intended Xcode app and inspect the live state. For Gale's Xcode beta work, check system-wide beta candidates such as `/Applications/Xcode-beta.app` and `/Applications/Betas/Xcode-beta.app`; for stable work, use `/Applications/Xcode.app`. Use command-scoped `DEVELOPER_DIR` for matching command-line checks instead of changing global `xcode-select` unless Gale asks for a global switch. ## Surface Classification diff --git a/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/references/source-evidence.md b/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/references/source-evidence.md index 35794afa..c8d13377 100644 --- a/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/references/source-evidence.md +++ b/plugins/apple-dev-skills/skills/xcode-coding-intelligence-workflow/references/source-evidence.md @@ -2,6 +2,8 @@ This reference records the first practical source set for the Xcode 27 coding-intelligence workflow. +Current path note: Gale now keeps Xcode betas in system-wide `/Applications` locations, including `/Applications/Xcode-beta.app` and sometimes `/Applications/Betas/Xcode-beta.app`. Older evidence below keeps the then-installed user-local path as historical evidence, not current guidance. + ## Checked 2026-06-22 ### Apple Developer @@ -26,7 +28,7 @@ Some Apple documentation pages are JavaScript-rendered. When a page body is not ### Local Xcode Tool Output -Checked with: +Checked with the then-installed beta path: ```bash DEVELOPER_DIR=/Users/galew/Applications/Betas/Xcode-beta.app/Contents/Developer xcodebuild -version @@ -64,7 +66,7 @@ Observed `mcpbridge` behavior: ### Local Xcode 27 Beta Live App Probe -Checked with Xcode 27 beta running from: +Checked with Xcode 27 beta running from the then-installed beta app path: ```text /Users/galew/Applications/Betas/Xcode-beta.app @@ -109,6 +111,26 @@ Observed import behavior: - `Add from URL` rejected `file:///private/tmp/socket-xcode-plugin-fixture/socket-xcode-fixture` as invalid. - `Add from URL` accepted `https://github.com/gaelic-ghost/socket.git` and enumerated Socket child plug-ins from the public repository before import. No additional Socket child plug-ins were imported from this URL during the probe. +## Checked 2026-07-02 + +### Current Local Xcode Beta Path + +Current system-wide beta path check: + +```bash +DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer xcodebuild -version +xcode-select -p +xcodebuild -version +``` + +Observed beta Xcode version: Xcode 27.0, build 27A5209h. + +Observed active developer directory: + +```text +/Applications/Xcode-beta.app/Contents/Developer +``` + Observed artifacts after import: - Xcode registered imported plug-ins in `~/Library/Developer/Xcode/CodingAssistant/AgentPlugins/PluginsManifest.json`. diff --git a/plugins/apple-dev-skills/skills/xcode-testing-workflow/references/toolchain-management.md b/plugins/apple-dev-skills/skills/xcode-testing-workflow/references/toolchain-management.md index ae395557..cc3664cf 100644 --- a/plugins/apple-dev-skills/skills/xcode-testing-workflow/references/toolchain-management.md +++ b/plugins/apple-dev-skills/skills/xcode-testing-workflow/references/toolchain-management.md @@ -11,12 +11,23 @@ - `xcodebuild -version` - `xcode-select -p` - `xcrun --find swift` +- `xcrun --find xcodebuild` - `xcodebuild -showComponent metalToolchain` ## Official Xcode and CLT actions -- Select active developer directory: - - `xcode-select --switch ` +- Select a toolchain for one command: + - `DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer xcodebuild -version` + - `DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer xcodebuild -version` + - `DEVELOPER_DIR=/Applications/Betas/Xcode-beta.app/Contents/Developer xcodebuild -version` +- Select the system-wide active developer directory only when the user explicitly wants the default CLI tools to change: + - record the current value first with `xcode-select -p` + - switch to stable Xcode with `sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer` + - switch to a beta Xcode with `sudo xcode-select --switch /Applications/Xcode-beta.app/Contents/Developer` or `sudo xcode-select --switch /Applications/Betas/Xcode-beta.app/Contents/Developer` + - verify with `xcode-select -p`, `xcodebuild -version`, and `xcrun --find swift` + - restore the previous path with another `sudo xcode-select --switch ` when the global beta test is finished +- Reset default command line tools path: + - `sudo xcode-select --reset` - Install/repair command line tools (interactive on macOS): - `xcode-select --install` @@ -24,6 +35,10 @@ - Prefer explicit output of versions and selected developer dir before diagnosing build/test failures. - Keep fallback commands deterministic and project-local. +- Prefer per-command `DEVELOPER_DIR` when checking a beta, reproducing a toolchain-specific issue, or avoiding changes that affect other shells, editors, CI helpers, and agents on the same Mac. +- Use `xcode-select --switch` when the task is intentionally about changing the default command-line tools selection. `xcode-select` controls tools discovered through `xcrun`, `xcodebuild`, and BSD development commands such as `cc` and `make`. +- Treat `/Applications/Xcode.app` as the usual stable Xcode path. For beta Xcode installs on Gale's MacBook, check system-wide candidates such as `/Applications/Xcode-beta.app` and `/Applications/Betas/Xcode-beta.app` instead of the older user-local `~/Applications/Betas` location. +- Do not use `xcode-select --install` as an Xcode app switch; it opens the interactive Command Line Tools installer. - When a Swift package build appears to depend on Xcode-managed assets or components, verify the active Xcode toolchain before defaulting to `swift build`. - `xcodebuild` may expose Apple-managed toolchain paths, including components like the Metal toolchain, that do not show up the same way through plain SwiftPM invocation. - When Metal shader compilation or packaged `.metallib` validation matters, verify the active Xcode component state and prefer explicit `xcodebuild` validation over assuming SwiftPM alone covers the Apple-managed build path. diff --git a/plugins/apple-dev-skills/tests/test_xcode_coding_intelligence_workflow.py b/plugins/apple-dev-skills/tests/test_xcode_coding_intelligence_workflow.py index e677a3e4..ced6f85b 100644 --- a/plugins/apple-dev-skills/tests/test_xcode_coding_intelligence_workflow.py +++ b/plugins/apple-dev-skills/tests/test_xcode_coding_intelligence_workflow.py @@ -34,6 +34,22 @@ def test_beta_claims_are_dated_and_bounded(self) -> None: self.assertIn("Earlier default-developer-dir check observed Xcode 26.5, build 17F42.", evidence_text) self.assertIn("Local Xcode 27 Beta Plug-in Import Probe", evidence_text) + def test_beta_path_guidance_uses_system_wide_app_locations(self) -> None: + skill_text = self.read("skills/xcode-coding-intelligence-workflow/SKILL.md") + bridge_text = self.read("skills/xcode-coding-intelligence-workflow/references/mcpbridge-and-external-agents.md") + setup_text = self.read("skills/xcode-coding-intelligence-workflow/references/setup-and-agent-surfaces.md") + evidence_text = self.read("skills/xcode-coding-intelligence-workflow/references/source-evidence.md") + + for text in (skill_text, bridge_text, setup_text): + self.assertIn("/Applications/Xcode-beta.app", text) + self.assertIn("/Applications/Betas/Xcode-beta.app", text) + self.assertIn("command-scoped `DEVELOPER_DIR`", text) + self.assertNotIn("/Users/galew/Applications/Betas", text) + + self.assertIn("Current path note", evidence_text) + self.assertIn("Observed beta Xcode version: Xcode 27.0, build 27A5209h.", evidence_text) + self.assertIn("historical evidence, not current guidance", evidence_text) + def test_external_agent_reference_documents_mcpbridge_preconditions(self) -> None: bridge_text = self.read("skills/xcode-coding-intelligence-workflow/references/mcpbridge-and-external-agents.md") diff --git a/plugins/apple-dev-skills/tests/test_xcode_toolchain_selection_guidance.py b/plugins/apple-dev-skills/tests/test_xcode_toolchain_selection_guidance.py new file mode 100644 index 00000000..0ed24ef8 --- /dev/null +++ b/plugins/apple-dev-skills/tests/test_xcode_toolchain_selection_guidance.py @@ -0,0 +1,49 @@ +from __future__ import annotations + +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +class XcodeToolchainSelectionGuidanceTests(unittest.TestCase): + def read(self, relative_path: str) -> str: + return (ROOT / relative_path).read_text(encoding="utf-8") + + def test_xcode_workflows_document_global_and_command_scoped_toolchain_selection(self) -> None: + references = [ + "skills/xcode-build-run-workflow/references/toolchain-management.md", + "skills/xcode-testing-workflow/references/toolchain-management.md", + "skills/xcode-app-project-workflow/references/toolchain-management.md", + ] + + for reference in references: + with self.subTest(reference=reference): + text = self.read(reference) + + self.assertIn("DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer", text) + self.assertIn("DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer", text) + self.assertIn("DEVELOPER_DIR=/Applications/Betas/Xcode-beta.app/Contents/Developer", text) + self.assertIn("sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer", text) + self.assertIn("sudo xcode-select --switch /Applications/Xcode-beta.app/Contents/Developer", text) + self.assertIn("sudo xcode-select --switch /Applications/Betas/Xcode-beta.app/Contents/Developer", text) + self.assertIn("record the current value first with `xcode-select -p`", text) + self.assertIn("restore the previous path", text) + self.assertIn("Do not use `xcode-select --install` as an Xcode app switch", text) + + def test_icon_composer_checks_system_wide_beta_paths(self) -> None: + text = self.read("skills/icon-composer-app-icon-workflow/SKILL.md") + + self.assertIn("/Applications/Xcode-beta.app/Contents/Applications/Icon Composer.app", text) + self.assertIn("/Applications/Betas/Xcode-beta.app/Contents/Applications/Icon Composer.app", text) + self.assertIn("/Applications/Xcode-beta.app/Contents/Applications/Icon Composer.app/Contents/Executables/ictool", text) + self.assertIn( + "/Applications/Betas/Xcode-beta.app/Contents/Applications/Icon Composer.app/Contents/Executables/ictool", + text, + ) + self.assertNotIn("/Users/galew/Applications/Betas", text) + + +if __name__ == "__main__": + unittest.main()