buildanything 1.7.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +9 -3
- package/CHANGELOG.md +112 -0
- package/README.md +2 -2
- package/agents/a11y-architect.md +166 -0
- package/agents/business-model.md +80 -29
- package/agents/code-architect.md +75 -0
- package/agents/code-reviewer.md +255 -0
- package/agents/code-simplifier.md +64 -0
- package/agents/design-brand-guardian.md +293 -53
- package/agents/design-critic.md +139 -0
- package/agents/design-inclusive-visuals-specialist.md +6 -19
- package/agents/design-ui-designer.md +335 -56
- package/agents/design-ux-architect.md +403 -55
- package/agents/design-ux-researcher.md +264 -49
- package/agents/engineering-ai-engineer.md +26 -36
- package/agents/engineering-backend-architect.md +185 -36
- package/agents/engineering-data-engineer.md +225 -43
- package/agents/engineering-devops-automator.md +227 -74
- package/agents/engineering-frontend-developer.md +210 -34
- package/agents/engineering-mobile-app-builder.md +6 -1
- package/agents/engineering-rapid-prototyper.md +30 -9
- package/agents/engineering-security-engineer.md +263 -61
- package/agents/engineering-senior-developer.md +128 -19
- package/agents/engineering-sre.md +84 -0
- package/agents/engineering-technical-writer.md +285 -41
- package/agents/feature-intel.md +110 -0
- package/agents/ios-app-review-guardian.md +66 -0
- package/agents/ios-foundation-models-specialist.md +64 -0
- package/agents/ios-storekit-specialist.md +59 -0
- package/agents/ios-swift-architect.md +129 -0
- package/agents/ios-swift-search.md +137 -0
- package/agents/ios-swift-ui-design.md +136 -0
- package/agents/marketing-app-store-optimizer.md +246 -64
- package/agents/planner.md +216 -0
- package/agents/pr-test-analyzer.md +63 -0
- package/agents/product-feedback-synthesizer.md +8 -2
- package/agents/refactor-cleaner.md +102 -0
- package/agents/security-reviewer.md +128 -0
- package/agents/silent-failure-hunter.md +54 -0
- package/agents/swift-build-resolver.md +119 -0
- package/agents/swift-reviewer.md +112 -0
- package/agents/tech-feasibility.md +21 -1
- package/agents/testing-api-tester.md +236 -59
- package/agents/testing-evidence-collector.md +26 -1
- package/agents/testing-performance-benchmarker.md +21 -1
- package/agents/testing-reality-checker.md +6 -1
- package/agents/visual-research.md +116 -0
- package/bin/adapters/cycle-counter-tool.ts +155 -0
- package/bin/adapters/scribe-tool.ts +71 -0
- package/bin/adapters/state-save-tool.ts +130 -0
- package/bin/adapters/write-lease-tool.ts +127 -0
- package/bin/buildanything-runtime.js +15 -0
- package/bin/buildanything-runtime.ts +328 -0
- package/bin/setup.js +83 -8
- package/commands/add-feature.md +2 -0
- package/commands/build.md +752 -332
- package/commands/fix.md +65 -0
- package/commands/self-check.md +121 -0
- package/commands/setup.md +114 -0
- package/commands/ux-review.md +63 -0
- package/commands/verify.md +69 -0
- package/docs/migration/agents.yaml +729 -0
- package/docs/migration/phase-graph.yaml +1088 -0
- package/docs/migration/sdk-host-compat.md +18 -0
- package/hooks/compile-writer-owner-cache.ts +171 -0
- package/hooks/hooks.json +36 -0
- package/hooks/pre-tool-use +19 -0
- package/hooks/pre-tool-use.ts +776 -0
- package/hooks/record-mode-transitions.ts +178 -0
- package/hooks/session-start +89 -2
- package/hooks/subagent-start +17 -0
- package/hooks/subagent-start.ts +471 -0
- package/hooks/subagent-stop +17 -0
- package/hooks/subagent-stop.ts +153 -0
- package/package.json +28 -5
- package/protocols/architecture-schema.md +171 -0
- package/protocols/build-fix.md +52 -0
- package/protocols/cleanup.md +54 -0
- package/protocols/decision-log.md +131 -0
- package/protocols/eval-harness.md +61 -0
- package/protocols/fake-data-detector.md +64 -0
- package/protocols/ios-context.md +234 -0
- package/protocols/ios-frameworks-map.md +323 -0
- package/protocols/ios-phase-branches.md +337 -0
- package/protocols/ios-preflight.md +27 -0
- package/protocols/launch-readiness.md +258 -0
- package/protocols/metric-loop.md +153 -0
- package/protocols/smoke-test.md +118 -0
- package/protocols/state-schema.json +388 -0
- package/protocols/state-schema.md +172 -0
- package/protocols/verify.md +127 -0
- package/protocols/visual-dna.md +185 -0
- package/protocols/web-phase-branches.md +351 -0
- package/skills/ios/_VENDORED.md +62 -0
- package/skills/ios/activitykit/LICENSE +131 -0
- package/skills/ios/activitykit/SKILL.md +505 -0
- package/skills/ios/activitykit/references/activitykit-patterns.md +868 -0
- package/skills/ios/app-intents/LICENSE +131 -0
- package/skills/ios/app-intents/SKILL.md +494 -0
- package/skills/ios/app-intents/references/appintents-advanced.md +1076 -0
- package/skills/ios/app-store-connect-metadata/SKILL.md +148 -0
- package/skills/ios/apple-on-device-ai/LICENSE +131 -0
- package/skills/ios/apple-on-device-ai/SKILL.md +505 -0
- package/skills/ios/apple-on-device-ai/references/coreml-conversion.md +425 -0
- package/skills/ios/apple-on-device-ai/references/coreml-optimization.md +344 -0
- package/skills/ios/apple-on-device-ai/references/foundation-models.md +508 -0
- package/skills/ios/apple-on-device-ai/references/mlx-swift.md +285 -0
- package/skills/ios/asc-privacy-manifest/SKILL.md +350 -0
- package/skills/ios/hig-components-content/SKILL.md +86 -0
- package/skills/ios/hig-components-content/references/activity-views.md +79 -0
- package/skills/ios/hig-components-content/references/charts.md +180 -0
- package/skills/ios/hig-components-content/references/collections.md +48 -0
- package/skills/ios/hig-components-content/references/color-wells.md +42 -0
- package/skills/ios/hig-components-content/references/image-views.md +82 -0
- package/skills/ios/hig-components-content/references/image-wells.md +34 -0
- package/skills/ios/hig-components-content/references/lockups.md +78 -0
- package/skills/ios/hig-components-content/references/web-views.md +36 -0
- package/skills/ios/hig-components-controls/SKILL.md +88 -0
- package/skills/ios/hig-components-controls/references/combo-boxes.md +40 -0
- package/skills/ios/hig-components-controls/references/controls.md +112 -0
- package/skills/ios/hig-components-controls/references/gauges.md +74 -0
- package/skills/ios/hig-components-controls/references/labels.md +92 -0
- package/skills/ios/hig-components-controls/references/pickers.md +128 -0
- package/skills/ios/hig-components-controls/references/rating-indicators.md +38 -0
- package/skills/ios/hig-components-controls/references/segmented-controls.md +94 -0
- package/skills/ios/hig-components-controls/references/sliders.md +92 -0
- package/skills/ios/hig-components-controls/references/steppers.md +40 -0
- package/skills/ios/hig-components-controls/references/text-fields.md +88 -0
- package/skills/ios/hig-components-controls/references/text-views.md +56 -0
- package/skills/ios/hig-components-controls/references/toggles.md +127 -0
- package/skills/ios/hig-components-controls/references/token-fields.md +48 -0
- package/skills/ios/hig-components-controls/references/virtual-keyboards.md +156 -0
- package/skills/ios/hig-components-dialogs/SKILL.md +76 -0
- package/skills/ios/hig-components-dialogs/references/action-sheets.md +74 -0
- package/skills/ios/hig-components-dialogs/references/alerts.md +158 -0
- package/skills/ios/hig-components-dialogs/references/digit-entry-views.md +32 -0
- package/skills/ios/hig-components-dialogs/references/popovers.md +81 -0
- package/skills/ios/hig-components-dialogs/references/sheets.md +157 -0
- package/skills/ios/hig-components-layout/SKILL.md +99 -0
- package/skills/ios/hig-components-layout/references/boxes.md +48 -0
- package/skills/ios/hig-components-layout/references/column-views.md +44 -0
- package/skills/ios/hig-components-layout/references/lists-and-tables.md +99 -0
- package/skills/ios/hig-components-layout/references/ornaments.md +56 -0
- package/skills/ios/hig-components-layout/references/outline-views.md +64 -0
- package/skills/ios/hig-components-layout/references/panels.md +75 -0
- package/skills/ios/hig-components-layout/references/scroll-views.md +123 -0
- package/skills/ios/hig-components-layout/references/sidebars.md +109 -0
- package/skills/ios/hig-components-layout/references/split-views.md +110 -0
- package/skills/ios/hig-components-layout/references/tab-bars.md +173 -0
- package/skills/ios/hig-components-layout/references/tab-views.md +68 -0
- package/skills/ios/hig-components-layout/references/windows.md +188 -0
- package/skills/ios/hig-components-menus/SKILL.md +81 -0
- package/skills/ios/hig-components-menus/references/action-button.md +61 -0
- package/skills/ios/hig-components-menus/references/buttons.md +261 -0
- package/skills/ios/hig-components-menus/references/context-menus.md +105 -0
- package/skills/ios/hig-components-menus/references/disclosure-controls.md +84 -0
- package/skills/ios/hig-components-menus/references/dock-menus.md +40 -0
- package/skills/ios/hig-components-menus/references/edit-menus.md +88 -0
- package/skills/ios/hig-components-menus/references/menus.md +171 -0
- package/skills/ios/hig-components-menus/references/pop-up-buttons.md +70 -0
- package/skills/ios/hig-components-menus/references/pull-down-buttons.md +77 -0
- package/skills/ios/hig-components-menus/references/the-menu-bar.md +303 -0
- package/skills/ios/hig-components-menus/references/toolbars.md +256 -0
- package/skills/ios/hig-components-search/SKILL.md +68 -0
- package/skills/ios/hig-components-search/references/page-controls.md +120 -0
- package/skills/ios/hig-components-search/references/path-controls.md +40 -0
- package/skills/ios/hig-components-search/references/search-fields.md +189 -0
- package/skills/ios/hig-components-status/SKILL.md +80 -0
- package/skills/ios/hig-components-status/references/activity-rings.md +105 -0
- package/skills/ios/hig-components-status/references/progress-indicators.md +116 -0
- package/skills/ios/hig-components-status/references/status-bars.md +38 -0
- package/skills/ios/hig-components-system/SKILL.md +88 -0
- package/skills/ios/hig-components-system/references/app-clips.md +387 -0
- package/skills/ios/hig-components-system/references/app-shortcuts.md +114 -0
- package/skills/ios/hig-components-system/references/complications.md +425 -0
- package/skills/ios/hig-components-system/references/home-screen-quick-actions.md +42 -0
- package/skills/ios/hig-components-system/references/live-activities.md +442 -0
- package/skills/ios/hig-components-system/references/notifications.md +153 -0
- package/skills/ios/hig-components-system/references/top-shelf.md +135 -0
- package/skills/ios/hig-components-system/references/watch-faces.md +40 -0
- package/skills/ios/hig-components-system/references/widgets.md +517 -0
- package/skills/ios/hig-foundations/SKILL.md +98 -0
- package/skills/ios/hig-foundations/references/accessibility.md +291 -0
- package/skills/ios/hig-foundations/references/app-icons.md +210 -0
- package/skills/ios/hig-foundations/references/branding.md +44 -0
- package/skills/ios/hig-foundations/references/color.md +274 -0
- package/skills/ios/hig-foundations/references/dark-mode.md +116 -0
- package/skills/ios/hig-foundations/references/icons.md +263 -0
- package/skills/ios/hig-foundations/references/images.md +176 -0
- package/skills/ios/hig-foundations/references/immersive-experiences.md +174 -0
- package/skills/ios/hig-foundations/references/inclusion.md +189 -0
- package/skills/ios/hig-foundations/references/layout.md +425 -0
- package/skills/ios/hig-foundations/references/materials.md +238 -0
- package/skills/ios/hig-foundations/references/motion.md +103 -0
- package/skills/ios/hig-foundations/references/privacy.md +231 -0
- package/skills/ios/hig-foundations/references/right-to-left.md +206 -0
- package/skills/ios/hig-foundations/references/sf-symbols.md +310 -0
- package/skills/ios/hig-foundations/references/spatial-layout.md +142 -0
- package/skills/ios/hig-foundations/references/typography.md +1146 -0
- package/skills/ios/hig-foundations/references/writing.md +91 -0
- package/skills/ios/hig-inputs/SKILL.md +94 -0
- package/skills/ios/hig-inputs/references/apple-pencil-and-scribble.md +148 -0
- package/skills/ios/hig-inputs/references/camera-control.md +107 -0
- package/skills/ios/hig-inputs/references/digital-crown.md +83 -0
- package/skills/ios/hig-inputs/references/eyes.md +120 -0
- package/skills/ios/hig-inputs/references/focus-and-selection.md +120 -0
- package/skills/ios/hig-inputs/references/game-controls.md +156 -0
- package/skills/ios/hig-inputs/references/gestures.md +208 -0
- package/skills/ios/hig-inputs/references/gyro-and-accelerometer.md +40 -0
- package/skills/ios/hig-inputs/references/keyboards.md +234 -0
- package/skills/ios/hig-inputs/references/nearby-interactions.md +70 -0
- package/skills/ios/hig-inputs/references/pointing-devices.md +237 -0
- package/skills/ios/hig-inputs/references/remotes.md +67 -0
- package/skills/ios/hig-inputs/references/spatial-interactions.md +70 -0
- package/skills/ios/hig-patterns/SKILL.md +104 -0
- package/skills/ios/hig-patterns/references/charting-data.md +81 -0
- package/skills/ios/hig-patterns/references/collaboration-and-sharing.md +86 -0
- package/skills/ios/hig-patterns/references/drag-and-drop.md +134 -0
- package/skills/ios/hig-patterns/references/entering-data.md +69 -0
- package/skills/ios/hig-patterns/references/feedback.md +67 -0
- package/skills/ios/hig-patterns/references/file-management.md +135 -0
- package/skills/ios/hig-patterns/references/going-full-screen.md +79 -0
- package/skills/ios/hig-patterns/references/launching.md +81 -0
- package/skills/ios/hig-patterns/references/live-viewing-apps.md +79 -0
- package/skills/ios/hig-patterns/references/loading.md +59 -0
- package/skills/ios/hig-patterns/references/managing-accounts.md +107 -0
- package/skills/ios/hig-patterns/references/managing-notifications.md +99 -0
- package/skills/ios/hig-patterns/references/modality.md +82 -0
- package/skills/ios/hig-patterns/references/multitasking.md +131 -0
- package/skills/ios/hig-patterns/references/offering-help.md +117 -0
- package/skills/ios/hig-patterns/references/onboarding.md +69 -0
- package/skills/ios/hig-patterns/references/playing-audio.md +124 -0
- package/skills/ios/hig-patterns/references/playing-haptics.md +280 -0
- package/skills/ios/hig-patterns/references/playing-video.md +180 -0
- package/skills/ios/hig-patterns/references/printing.md +50 -0
- package/skills/ios/hig-patterns/references/ratings-and-reviews.md +48 -0
- package/skills/ios/hig-patterns/references/searching.md +70 -0
- package/skills/ios/hig-patterns/references/settings.md +84 -0
- package/skills/ios/hig-patterns/references/undo-and-redo.md +58 -0
- package/skills/ios/hig-patterns/references/workouts.md +76 -0
- package/skills/ios/hig-platforms/SKILL.md +84 -0
- package/skills/ios/hig-platforms/references/designing-for-games.md +159 -0
- package/skills/ios/hig-platforms/references/designing-for-ios.md +66 -0
- package/skills/ios/hig-platforms/references/designing-for-ipados.md +64 -0
- package/skills/ios/hig-platforms/references/designing-for-macos.md +70 -0
- package/skills/ios/hig-platforms/references/designing-for-tvos.md +68 -0
- package/skills/ios/hig-platforms/references/designing-for-visionos.md +85 -0
- package/skills/ios/hig-platforms/references/designing-for-watchos.md +74 -0
- package/skills/ios/hig-project-context/SKILL.md +133 -0
- package/skills/ios/hig-technologies/SKILL.md +107 -0
- package/skills/ios/hig-technologies/references/airplay.md +125 -0
- package/skills/ios/hig-technologies/references/always-on.md +62 -0
- package/skills/ios/hig-technologies/references/apple-pay.md +441 -0
- package/skills/ios/hig-technologies/references/augmented-reality.md +247 -0
- package/skills/ios/hig-technologies/references/carekit.md +224 -0
- package/skills/ios/hig-technologies/references/carplay.md +119 -0
- package/skills/ios/hig-technologies/references/game-center.md +343 -0
- package/skills/ios/hig-technologies/references/generative-ai.md +110 -0
- package/skills/ios/hig-technologies/references/healthkit.md +120 -0
- package/skills/ios/hig-technologies/references/homekit.md +343 -0
- package/skills/ios/hig-technologies/references/icloud.md +52 -0
- package/skills/ios/hig-technologies/references/id-verifier.md +73 -0
- package/skills/ios/hig-technologies/references/imessage-apps-and-stickers.md +105 -0
- package/skills/ios/hig-technologies/references/in-app-purchase.md +263 -0
- package/skills/ios/hig-technologies/references/live-photos.md +54 -0
- package/skills/ios/hig-technologies/references/mac-catalyst.md +216 -0
- package/skills/ios/hig-technologies/references/machine-learning.md +394 -0
- package/skills/ios/hig-technologies/references/maps.md +221 -0
- package/skills/ios/hig-technologies/references/nfc.md +51 -0
- package/skills/ios/hig-technologies/references/photo-editing.md +40 -0
- package/skills/ios/hig-technologies/references/researchkit.md +134 -0
- package/skills/ios/hig-technologies/references/shareplay.md +142 -0
- package/skills/ios/hig-technologies/references/shazamkit.md +47 -0
- package/skills/ios/hig-technologies/references/sign-in-with-apple.md +288 -0
- package/skills/ios/hig-technologies/references/siri.md +523 -0
- package/skills/ios/hig-technologies/references/tap-to-pay-on-iphone.md +208 -0
- package/skills/ios/hig-technologies/references/voiceover.md +90 -0
- package/skills/ios/hig-technologies/references/wallet.md +420 -0
- package/skills/ios/ios-26-platform/SKILL.md +53 -0
- package/skills/ios/ios-26-platform/references/automatic-adoption.md +161 -0
- package/skills/ios/ios-26-platform/references/backward-compat.md +238 -0
- package/skills/ios/ios-26-platform/references/liquid-glass.md +255 -0
- package/skills/ios/ios-26-platform/references/swiftui-apis.md +277 -0
- package/skills/ios/ios-26-platform/references/toolbar-navigation.md +250 -0
- package/skills/ios/ios-bootstrap/SKILL.md +107 -0
- package/skills/ios/ios-bootstrap/references/apple-docs-mcp-config.md +28 -0
- package/skills/ios/ios-bootstrap/references/new-project-dialog.md +41 -0
- package/skills/ios/ios-bootstrap/references/xcode-mcp-config.md +29 -0
- package/skills/ios/ios-debugger-agent/LICENSE +21 -0
- package/skills/ios/ios-debugger-agent/SKILL.md +58 -0
- package/skills/ios/ios-debugger-agent/agents/openai.yaml +4 -0
- package/skills/ios/ios-entitlements-generator/SKILL.md +47 -0
- package/skills/ios/ios-info-plist-hardening/SKILL.md +130 -0
- package/skills/ios/ios-maestro-flow-author/SKILL.md +68 -0
- package/skills/ios/ios-maestro-flow-author/references/input-and-scroll.yaml +17 -0
- package/skills/ios/ios-maestro-flow-author/references/modal-and-dismiss.yaml +14 -0
- package/skills/ios/ios-maestro-flow-author/references/onboarding-flow.yaml +16 -0
- package/skills/ios/ios-maestro-flow-author/references/tab-navigation.yaml +13 -0
- package/skills/ios/ios-maestro-flow-author/references/tap-and-assert.yaml +9 -0
- package/skills/ios/swift-accessibility/LICENSE +21 -0
- package/skills/ios/swift-accessibility/SKILL.md +371 -0
- package/skills/ios/swift-accessibility/examples/before-after-appkit.md +446 -0
- package/skills/ios/swift-accessibility/examples/before-after-swiftui.md +441 -0
- package/skills/ios/swift-accessibility/examples/before-after-uikit.md +464 -0
- package/skills/ios/swift-accessibility/references/assistive-access.md +441 -0
- package/skills/ios/swift-accessibility/references/display-settings.md +491 -0
- package/skills/ios/swift-accessibility/references/dynamic-type.md +420 -0
- package/skills/ios/swift-accessibility/references/media-accessibility.md +421 -0
- package/skills/ios/swift-accessibility/references/motor-input.md +393 -0
- package/skills/ios/swift-accessibility/references/nutrition-labels.md +362 -0
- package/skills/ios/swift-accessibility/references/platform-specifics.md +515 -0
- package/skills/ios/swift-accessibility/references/semantic-structure.md +585 -0
- package/skills/ios/swift-accessibility/references/testing-auditing.md +507 -0
- package/skills/ios/swift-accessibility/references/voice-control.md +317 -0
- package/skills/ios/swift-accessibility/references/voiceover-swiftui.md +584 -0
- package/skills/ios/swift-accessibility/references/voiceover-uikit.md +519 -0
- package/skills/ios/swift-accessibility/references/wcag-mapping.md +167 -0
- package/skills/ios/swift-accessibility/resources/audit-template.swift +128 -0
- package/skills/ios/swift-accessibility/resources/qa-checklist.md +258 -0
- package/skills/ios/swift-actor-persistence/SKILL.md +143 -0
- package/skills/ios/swift-concurrency/LICENSE +21 -0
- package/skills/ios/swift-concurrency/SKILL.md +171 -0
- package/skills/ios/swift-concurrency/references/_index.md +50 -0
- package/skills/ios/swift-concurrency/references/actors.md +660 -0
- package/skills/ios/swift-concurrency/references/async-algorithms.md +847 -0
- package/skills/ios/swift-concurrency/references/async-await-basics.md +266 -0
- package/skills/ios/swift-concurrency/references/async-sequences.md +710 -0
- package/skills/ios/swift-concurrency/references/core-data.md +560 -0
- package/skills/ios/swift-concurrency/references/glossary.md +135 -0
- package/skills/ios/swift-concurrency/references/linting.md +155 -0
- package/skills/ios/swift-concurrency/references/memory-management.md +569 -0
- package/skills/ios/swift-concurrency/references/migration.md +1104 -0
- package/skills/ios/swift-concurrency/references/performance.md +593 -0
- package/skills/ios/swift-concurrency/references/sendable.md +598 -0
- package/skills/ios/swift-concurrency/references/tasks.md +636 -0
- package/skills/ios/swift-concurrency/references/testing.md +592 -0
- package/skills/ios/swift-concurrency/references/threading.md +495 -0
- package/skills/ios/swift-concurrency-6-2/SKILL.md +216 -0
- package/skills/ios/swift-protocol-di-testing/SKILL.md +190 -0
- package/skills/ios/swift-security-expert/LICENSE +21 -0
- package/skills/ios/swift-security-expert/SKILL.md +470 -0
- package/skills/ios/swift-security-expert/references/biometric-authentication.md +565 -0
- package/skills/ios/swift-security-expert/references/certificate-trust.md +592 -0
- package/skills/ios/swift-security-expert/references/common-anti-patterns.md +690 -0
- package/skills/ios/swift-security-expert/references/compliance-owasp-mapping.md +537 -0
- package/skills/ios/swift-security-expert/references/credential-storage-patterns.md +721 -0
- package/skills/ios/swift-security-expert/references/cryptokit-public-key.md +505 -0
- package/skills/ios/swift-security-expert/references/cryptokit-symmetric.md +497 -0
- package/skills/ios/swift-security-expert/references/keychain-access-control.md +508 -0
- package/skills/ios/swift-security-expert/references/keychain-fundamentals.md +596 -0
- package/skills/ios/swift-security-expert/references/keychain-item-classes.md +476 -0
- package/skills/ios/swift-security-expert/references/keychain-sharing.md +458 -0
- package/skills/ios/swift-security-expert/references/migration-legacy-stores.md +727 -0
- package/skills/ios/swift-security-expert/references/secure-enclave.md +539 -0
- package/skills/ios/swift-security-expert/references/testing-security-code.md +781 -0
- package/skills/ios/swift-testing-expert/LICENSE +21 -0
- package/skills/ios/swift-testing-expert/SKILL.md +79 -0
- package/skills/ios/swift-testing-expert/references/_index.md +12 -0
- package/skills/ios/swift-testing-expert/references/async-testing-and-waiting.md +127 -0
- package/skills/ios/swift-testing-expert/references/expectations.md +145 -0
- package/skills/ios/swift-testing-expert/references/fundamentals.md +141 -0
- package/skills/ios/swift-testing-expert/references/migration-from-xctest.md +127 -0
- package/skills/ios/swift-testing-expert/references/parallelization-and-isolation.md +95 -0
- package/skills/ios/swift-testing-expert/references/parameterized-testing.md +284 -0
- package/skills/ios/swift-testing-expert/references/performance-and-best-practices.md +187 -0
- package/skills/ios/swift-testing-expert/references/traits-and-tags.md +114 -0
- package/skills/ios/swift-testing-expert/references/xcode-workflows.md +70 -0
- package/skills/ios/swiftdata-pro/LICENSE +21 -0
- package/skills/ios/swiftdata-pro/SKILL.md +102 -0
- package/skills/ios/swiftdata-pro/agents/openai.yaml +10 -0
- package/skills/ios/swiftdata-pro/assets/swiftdata-pro-icon.png +0 -0
- package/skills/ios/swiftdata-pro/assets/swiftdata-pro-icon.svg +29 -0
- package/skills/ios/swiftdata-pro/references/class-inheritance.md +104 -0
- package/skills/ios/swiftdata-pro/references/cloudkit.md +10 -0
- package/skills/ios/swiftdata-pro/references/core-rules.md +20 -0
- package/skills/ios/swiftdata-pro/references/indexing.md +27 -0
- package/skills/ios/swiftdata-pro/references/predicates.md +73 -0
- package/skills/ios/swiftui-design-principles/AGENTS.md +21 -0
- package/skills/ios/swiftui-design-principles/LICENSE +21 -0
- package/skills/ios/swiftui-design-principles/README.md +41 -0
- package/skills/ios/swiftui-design-principles/SKILL.md +605 -0
- package/skills/ios/swiftui-design-principles/metadata.json +10 -0
- package/skills/ios/swiftui-design-tokens/SKILL.md +475 -0
- package/skills/ios/swiftui-liquid-glass/LICENSE +21 -0
- package/skills/ios/swiftui-liquid-glass/SKILL.md +95 -0
- package/skills/ios/swiftui-liquid-glass/agents/openai.yaml +4 -0
- package/skills/ios/swiftui-liquid-glass/references/liquid-glass.md +280 -0
- package/skills/ios/swiftui-performance-audit/LICENSE +21 -0
- package/skills/ios/swiftui-performance-audit/SKILL.md +111 -0
- package/skills/ios/swiftui-performance-audit/agents/openai.yaml +4 -0
- package/skills/ios/swiftui-performance-audit/references/code-smells.md +150 -0
- package/skills/ios/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
- package/skills/ios/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
- package/skills/ios/swiftui-performance-audit/references/profiling-intake.md +44 -0
- package/skills/ios/swiftui-performance-audit/references/report-template.md +47 -0
- package/skills/ios/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
- package/skills/ios/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
- package/skills/ios/swiftui-pro/LICENSE +21 -0
- package/skills/ios/swiftui-pro/SKILL.md +108 -0
- package/skills/ios/swiftui-pro/agents/openai.yaml +10 -0
- package/skills/ios/swiftui-pro/assets/swiftui-pro-icon.png +0 -0
- package/skills/ios/swiftui-pro/assets/swiftui-pro-icon.svg +29 -0
- package/skills/ios/swiftui-pro/references/accessibility.md +13 -0
- package/skills/ios/swiftui-pro/references/api.md +39 -0
- package/skills/ios/swiftui-pro/references/data.md +43 -0
- package/skills/ios/swiftui-pro/references/design.md +31 -0
- package/skills/ios/swiftui-pro/references/hygiene.md +9 -0
- package/skills/ios/swiftui-pro/references/navigation.md +14 -0
- package/skills/ios/swiftui-pro/references/performance.md +46 -0
- package/skills/ios/swiftui-pro/references/swift.md +56 -0
- package/skills/ios/swiftui-pro/references/views.md +35 -0
- package/skills/ios/swiftui-ui-patterns/LICENSE +21 -0
- package/skills/ios/swiftui-ui-patterns/SKILL.md +100 -0
- package/skills/ios/swiftui-ui-patterns/agents/openai.yaml +4 -0
- package/skills/ios/swiftui-ui-patterns/references/app-wiring.md +201 -0
- package/skills/ios/swiftui-ui-patterns/references/async-state.md +96 -0
- package/skills/ios/swiftui-ui-patterns/references/components-index.md +50 -0
- package/skills/ios/swiftui-ui-patterns/references/controls.md +57 -0
- package/skills/ios/swiftui-ui-patterns/references/deeplinks.md +66 -0
- package/skills/ios/swiftui-ui-patterns/references/focus.md +90 -0
- package/skills/ios/swiftui-ui-patterns/references/form.md +97 -0
- package/skills/ios/swiftui-ui-patterns/references/grids.md +71 -0
- package/skills/ios/swiftui-ui-patterns/references/haptics.md +71 -0
- package/skills/ios/swiftui-ui-patterns/references/input-toolbar.md +51 -0
- package/skills/ios/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
- package/skills/ios/swiftui-ui-patterns/references/list.md +86 -0
- package/skills/ios/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
- package/skills/ios/swiftui-ui-patterns/references/macos-settings.md +71 -0
- package/skills/ios/swiftui-ui-patterns/references/matched-transitions.md +59 -0
- package/skills/ios/swiftui-ui-patterns/references/media.md +73 -0
- package/skills/ios/swiftui-ui-patterns/references/menu-bar.md +101 -0
- package/skills/ios/swiftui-ui-patterns/references/navigationstack.md +159 -0
- package/skills/ios/swiftui-ui-patterns/references/overlay.md +45 -0
- package/skills/ios/swiftui-ui-patterns/references/performance.md +62 -0
- package/skills/ios/swiftui-ui-patterns/references/previews.md +48 -0
- package/skills/ios/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
- package/skills/ios/swiftui-ui-patterns/references/scrollview.md +87 -0
- package/skills/ios/swiftui-ui-patterns/references/searchable.md +71 -0
- package/skills/ios/swiftui-ui-patterns/references/sheets.md +155 -0
- package/skills/ios/swiftui-ui-patterns/references/split-views.md +72 -0
- package/skills/ios/swiftui-ui-patterns/references/tabview.md +114 -0
- package/skills/ios/swiftui-ui-patterns/references/theming.md +71 -0
- package/skills/ios/swiftui-ui-patterns/references/title-menus.md +93 -0
- package/skills/ios/swiftui-ui-patterns/references/top-bar.md +49 -0
- package/skills/ios/swiftui-view-refactor/LICENSE +21 -0
- package/skills/ios/swiftui-view-refactor/SKILL.md +207 -0
- package/skills/ios/swiftui-view-refactor/agents/openai.yaml +4 -0
- package/skills/ios/swiftui-view-refactor/references/mv-patterns.md +161 -0
- package/skills/ios/widgetkit/LICENSE +131 -0
- package/skills/ios/widgetkit/SKILL.md +502 -0
- package/skills/ios/widgetkit/references/widgetkit-advanced.md +871 -0
- package/skills/ios/writing-for-interfaces/SKILL.md +75 -0
- package/skills/web/accessibility/SKILL.md +146 -0
- package/skills/web/aceternity-ui/SKILL.md +719 -0
- package/skills/web/aceternity-ui/metadata.json +10 -0
- package/skills/web/api-design/SKILL.md +523 -0
- package/skills/web/chart-accessibility/SKILL.md +332 -0
- package/skills/web/composition-patterns/AGENTS.md +946 -0
- package/skills/web/composition-patterns/README.md +60 -0
- package/skills/web/composition-patterns/SKILL.md +89 -0
- package/skills/web/composition-patterns/metadata.json +11 -0
- package/skills/web/composition-patterns/rules/_sections.md +29 -0
- package/skills/web/composition-patterns/rules/_template.md +24 -0
- package/skills/web/composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
- package/skills/web/composition-patterns/rules/architecture-compound-components.md +112 -0
- package/skills/web/composition-patterns/rules/patterns-children-over-render-props.md +87 -0
- package/skills/web/composition-patterns/rules/patterns-explicit-variants.md +100 -0
- package/skills/web/composition-patterns/rules/react19-no-forwardref.md +42 -0
- package/skills/web/composition-patterns/rules/state-context-interface.md +191 -0
- package/skills/web/composition-patterns/rules/state-decouple-implementation.md +113 -0
- package/skills/web/composition-patterns/rules/state-lift-state.md +125 -0
- package/skills/web/cost-aware-llm-pipeline/SKILL.md +183 -0
- package/skills/web/database-migrations/SKILL.md +429 -0
- package/skills/web/deployment-patterns/SKILL.md +427 -0
- package/skills/web/docker-patterns/SKILL.md +364 -0
- package/skills/web/e2e-testing/SKILL.md +326 -0
- package/skills/web/lighthouse-ci/SKILL.md +361 -0
- package/skills/web/mcp-server-patterns/SKILL.md +69 -0
- package/skills/web/next-best-practices/SKILL.md +153 -0
- package/skills/web/next-best-practices/async-patterns.md +87 -0
- package/skills/web/next-best-practices/bundling.md +180 -0
- package/skills/web/next-best-practices/data-patterns.md +297 -0
- package/skills/web/next-best-practices/debug-tricks.md +105 -0
- package/skills/web/next-best-practices/directives.md +73 -0
- package/skills/web/next-best-practices/error-handling.md +227 -0
- package/skills/web/next-best-practices/file-conventions.md +140 -0
- package/skills/web/next-best-practices/font.md +245 -0
- package/skills/web/next-best-practices/functions.md +108 -0
- package/skills/web/next-best-practices/hydration-error.md +91 -0
- package/skills/web/next-best-practices/image.md +173 -0
- package/skills/web/next-best-practices/metadata.md +301 -0
- package/skills/web/next-best-practices/parallel-routes.md +287 -0
- package/skills/web/next-best-practices/route-handlers.md +146 -0
- package/skills/web/next-best-practices/rsc-boundaries.md +159 -0
- package/skills/web/next-best-practices/runtime-selection.md +39 -0
- package/skills/web/next-best-practices/scripts.md +141 -0
- package/skills/web/next-best-practices/self-hosting.md +371 -0
- package/skills/web/next-best-practices/suspense-boundaries.md +67 -0
- package/skills/web/next-cache-components/SKILL.md +411 -0
- package/skills/web/postgres-best-practices/SKILL.md +14 -0
- package/skills/web/postgres-best-practices/references/schema-design.md +9 -0
- package/skills/web/react-best-practices/AGENTS.md +3810 -0
- package/skills/web/react-best-practices/README.md +123 -0
- package/skills/web/react-best-practices/SKILL.md +149 -0
- package/skills/web/react-best-practices/metadata.json +15 -0
- package/skills/web/react-best-practices/rules/_sections.md +46 -0
- package/skills/web/react-best-practices/rules/_template.md +28 -0
- package/skills/web/react-best-practices/rules/advanced-effect-event-deps.md +56 -0
- package/skills/web/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/skills/web/react-best-practices/rules/advanced-init-once.md +42 -0
- package/skills/web/react-best-practices/rules/advanced-use-latest.md +39 -0
- package/skills/web/react-best-practices/rules/async-api-routes.md +38 -0
- package/skills/web/react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/skills/web/react-best-practices/rules/async-defer-await.md +82 -0
- package/skills/web/react-best-practices/rules/async-dependencies.md +51 -0
- package/skills/web/react-best-practices/rules/async-parallel.md +28 -0
- package/skills/web/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/skills/web/react-best-practices/rules/bundle-analyzable-paths.md +63 -0
- package/skills/web/react-best-practices/rules/bundle-barrel-imports.md +60 -0
- package/skills/web/react-best-practices/rules/bundle-conditional.md +31 -0
- package/skills/web/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/skills/web/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/skills/web/react-best-practices/rules/bundle-preload.md +50 -0
- package/skills/web/react-best-practices/rules/client-event-listeners.md +74 -0
- package/skills/web/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/skills/web/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/skills/web/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/skills/web/react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/skills/web/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/skills/web/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/skills/web/react-best-practices/rules/js-cache-storage.md +70 -0
- package/skills/web/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/skills/web/react-best-practices/rules/js-early-exit.md +50 -0
- package/skills/web/react-best-practices/rules/js-flatmap-filter.md +60 -0
- package/skills/web/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/skills/web/react-best-practices/rules/js-index-maps.md +37 -0
- package/skills/web/react-best-practices/rules/js-length-check-first.md +49 -0
- package/skills/web/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/skills/web/react-best-practices/rules/js-request-idle-callback.md +105 -0
- package/skills/web/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/skills/web/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/skills/web/react-best-practices/rules/rendering-activity.md +26 -0
- package/skills/web/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/skills/web/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/skills/web/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/skills/web/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/skills/web/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/skills/web/react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/skills/web/react-best-practices/rules/rendering-resource-hints.md +85 -0
- package/skills/web/react-best-practices/rules/rendering-script-defer-async.md +68 -0
- package/skills/web/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/skills/web/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/skills/web/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/skills/web/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/skills/web/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/skills/web/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/skills/web/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/skills/web/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/skills/web/react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/skills/web/react-best-practices/rules/rerender-memo.md +44 -0
- package/skills/web/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/skills/web/react-best-practices/rules/rerender-no-inline-components.md +82 -0
- package/skills/web/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/skills/web/react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/skills/web/react-best-practices/rules/rerender-transitions.md +40 -0
- package/skills/web/react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/skills/web/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/skills/web/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/skills/web/react-best-practices/rules/server-auth-actions.md +96 -0
- package/skills/web/react-best-practices/rules/server-cache-lru.md +41 -0
- package/skills/web/react-best-practices/rules/server-cache-react.md +76 -0
- package/skills/web/react-best-practices/rules/server-dedup-props.md +65 -0
- package/skills/web/react-best-practices/rules/server-hoist-static-io.md +149 -0
- package/skills/web/react-best-practices/rules/server-no-shared-module-state.md +50 -0
- package/skills/web/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/skills/web/react-best-practices/rules/server-parallel-nested-fetching.md +34 -0
- package/skills/web/react-best-practices/rules/server-serialization.md +38 -0
- package/skills/web/seo/SKILL.md +154 -0
- package/skills/web/web-design-guidelines/SKILL.md +39 -0
- package/skills/web/zap-scan-config/SKILL.md +444 -0
- package/skills/web/zap-scan-config/assets/.gitkeep +9 -0
- package/skills/web/zap-scan-config/assets/github_action.yml +207 -0
- package/skills/web/zap-scan-config/assets/gitlab_ci.yml +226 -0
- package/skills/web/zap-scan-config/assets/zap_automation.yaml +196 -0
- package/skills/web/zap-scan-config/assets/zap_context.xml +192 -0
- package/skills/web/zap-scan-config/references/EXAMPLE.md +40 -0
- package/skills/web/zap-scan-config/references/api_testing_guide.md +475 -0
- package/skills/web/zap-scan-config/references/authentication_guide.md +431 -0
- package/skills/web/zap-scan-config/references/false_positive_handling.md +427 -0
- package/skills/web/zap-scan-config/references/owasp_mapping.md +255 -0
- package/src/lrr/aggregator.ts +80 -0
- package/src/orchestrator/hooks/context-header.ts +95 -0
- package/src/orchestrator/hooks/token-accounting-emitter.ts +77 -0
- package/src/orchestrator/hooks/token-accounting.ts +101 -0
- package/src/orchestrator/mcp/cycle-counter.ts +129 -0
- package/src/orchestrator/mcp/scribe.ts +283 -0
- package/src/orchestrator/mcp/state-save.ts +149 -0
- package/src/orchestrator/mcp/write-lease.ts +167 -0
- package/src/orchestrator/phase4-shared-context.ts +41 -0
- package/src/orchestrator/schemas/backward-edge.ts +46 -0
- package/agents/agentic-identity-trust.md +0 -121
- package/agents/data-consolidation-agent.md +0 -39
- package/agents/design-image-prompt-engineer.md +0 -105
- package/agents/design-visual-storyteller.md +0 -147
- package/agents/design-whimsy-injector.md +0 -89
- package/agents/engineering-autonomous-optimization-architect.md +0 -105
- package/agents/market-intel.md +0 -35
- package/agents/marketing-instagram-curator.md +0 -111
- package/agents/marketing-reddit-community-builder.md +0 -121
- package/agents/marketing-social-media-strategist.md +0 -74
- package/agents/marketing-tiktok-strategist.md +0 -123
- package/agents/marketing-twitter-engager.md +0 -124
- package/agents/marketing-wechat-official-account.md +0 -143
- package/agents/marketing-xiaohongshu-specialist.md +0 -136
- package/agents/marketing-zhihu-strategist.md +0 -160
- package/agents/product-behavioral-nudge-engine.md +0 -78
- package/agents/project-management-experiment-tracker.md +0 -102
- package/agents/report-distribution-agent.md +0 -43
- package/agents/risk-analysis.md +0 -45
- package/agents/sales-data-extraction-agent.md +0 -46
- package/agents/specialized-cultural-intelligence-strategist.md +0 -65
- package/agents/specialized-developer-advocate.md +0 -146
- package/agents/support-analytics-reporter.md +0 -133
- package/agents/support-executive-summary-generator.md +0 -64
- package/agents/support-finance-tracker.md +0 -145
- package/agents/support-legal-compliance-checker.md +0 -129
- package/agents/support-support-responder.md +0 -91
- package/agents/testing-accessibility-auditor.md +0 -110
- package/agents/testing-test-results-analyzer.md +0 -97
- package/agents/testing-tool-evaluator.md +0 -76
- package/agents/testing-workflow-optimizer.md +0 -99
- package/agents/user-research.md +0 -40
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
# Keychain Access Control
|
|
2
|
+
|
|
3
|
+
> Scope: Selecting `kSecAttrAccessible` classes and `SecAccessControl` flags to enforce the correct lock-state and user-presence guarantees for keychain items.
|
|
4
|
+
|
|
5
|
+
Data protection classes (`kSecAttrAccessible`) and runtime authentication gates (`SecAccessControl`) form the two-layer security model protecting every keychain item. The first controls **when** an item's class key is available in memory based on device state; the second controls **how** the user must authenticate at access time. Both must be satisfied for a read to succeed. Getting this wrong is the single most common cause of production keychain failures — background operations that silently return `nil`, items that vanish after device migration, or credentials left decryptable at rest.
|
|
6
|
+
|
|
7
|
+
Sources: Apple Platform Security Guide (2024–2026 editions), Apple Keychain Services documentation, TN3137, WWDC 2014 Session 711 ("Keychain and Authentication with Touch ID"), WWDC 2015 Session 706, SecAccessControl documentation, OWASP MASTG.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## The "When" Layer: Seven Accessibility Constants
|
|
12
|
+
|
|
13
|
+
Every keychain item is encrypted with a class key derived from the device's hardware UID and (for most classes) the user's passcode. The `kSecAttrAccessible` attribute selects which class key protects the item, determining when the system can decrypt it. **If you omit `kSecAttrAccessible`, the default is `kSecAttrAccessibleWhenUnlocked`** — confirmed by Apple documentation. This default breaks all background operations.
|
|
14
|
+
|
|
15
|
+
### The Protection Spectrum
|
|
16
|
+
|
|
17
|
+
Listed from most restrictive to least:
|
|
18
|
+
|
|
19
|
+
**`kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly`** (iOS 8+) — the highest-security class. Items are accessible only while unlocked, and only if a device passcode is currently set. Two unique behaviors: (1) `SecItemAdd` fails on devices without a passcode, (2) **removing the passcode permanently deletes all items in this class** — class keys are discarded, data is unrecoverable. No non-`ThisDeviceOnly` variant exists. Items don't sync to iCloud Keychain, aren't backed up, and aren't in escrow keybags.
|
|
20
|
+
|
|
21
|
+
**`kSecAttrAccessibleWhenUnlockedThisDeviceOnly`** — Items decryptable only while unlocked. Device-bound: excluded from backups and device migration.
|
|
22
|
+
|
|
23
|
+
**`kSecAttrAccessibleWhenUnlocked`** ⭐ (system default) — Same lock-state behavior as above, but items migrate with encrypted backups. Maps to `NSFileProtectionComplete`. Class key is discarded from memory shortly after the device locks (~10 seconds with Require Password set to Immediately).
|
|
24
|
+
|
|
25
|
+
**`kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly`** — **The correct choice for background operations.** After the user unlocks the device once following a restart, the class key remains in memory until the next restart — even while locked. Device-bound.
|
|
26
|
+
|
|
27
|
+
**`kSecAttrAccessibleAfterFirstUnlock`** — Same background accessibility, but items migrate with encrypted backups. Apple uses this for system Wi-Fi passwords, mail accounts, and iCloud tokens. Maps to `NSFileProtectionCompleteUntilFirstUserAuthentication`.
|
|
28
|
+
|
|
29
|
+
**`kSecAttrAccessibleAlwaysThisDeviceOnly`** ⚠️ DEPRECATED — Deprecated in iOS 12 / macOS 10.14. Apple announced intent at WWDC 2015 Session 706.
|
|
30
|
+
|
|
31
|
+
**`kSecAttrAccessibleAlways`** ⚠️ DEPRECATED — Same deprecation. Items encrypted with only the device UID (no passcode involvement), equivalent to `NSFileProtectionNone`.
|
|
32
|
+
|
|
33
|
+
> **Cross-validation note — deprecated "Always" runtime behavior:** One research source reports these constants "still function at runtime" with original semantics on iOS 15–18. The other reports modern iOS silently remaps them to `AfterFirstUnlock` behavior. The practical guidance is identical either way: **migrate immediately to `kSecAttrAccessibleAfterFirstUnlock`**. Block these constants in CI linting. Do not rely on any specific runtime behavior for deprecated constants across OS versions.
|
|
34
|
+
|
|
35
|
+
### Quick Reference Table
|
|
36
|
+
|
|
37
|
+
| Constant | Accessible When | Survives Lock | Migrates in Backup | Special |
|
|
38
|
+
| -------------------------------- | ----------------------- | ------------- | ------------------ | ------------------------------- |
|
|
39
|
+
| `WhenPasscodeSetThisDeviceOnly` | Unlocked + passcode set | No | No | **Deleted on passcode removal** |
|
|
40
|
+
| `WhenUnlockedThisDeviceOnly` | Unlocked | No | No | — |
|
|
41
|
+
| `WhenUnlocked` ⭐ default | Unlocked | No | Yes | — |
|
|
42
|
+
| `AfterFirstUnlockThisDeviceOnly` | After first unlock | Yes | No | Background-safe |
|
|
43
|
+
| `AfterFirstUnlock` | After first unlock | Yes | Yes | Background-safe + migratable |
|
|
44
|
+
| `AlwaysThisDeviceOnly` ⚠️ | Always¹ | Yes | No | Deprecated iOS 12 |
|
|
45
|
+
| `Always` ⚠️ | Always¹ | Yes | Yes | Deprecated iOS 12 |
|
|
46
|
+
|
|
47
|
+
¹ Behavior may be remapped to `AfterFirstUnlock` on modern iOS versions.
|
|
48
|
+
|
|
49
|
+
### Lock-State Spectrum Explained
|
|
50
|
+
|
|
51
|
+
After a device restart, the system is in **Before First Unlock (BFU)** state. Only items with the deprecated `Always` class are supposed to be accessible. Even `AfterFirstUnlock` items are locked.
|
|
52
|
+
|
|
53
|
+
Once the user enters their passcode, the device enters **After First Unlock (AFU)** state. `AfterFirstUnlock` class keys load into memory and remain there through subsequent lock/unlock cycles until the next restart. `WhenUnlocked` class keys are available only during active unlocked periods and discarded each time the device locks.
|
|
54
|
+
|
|
55
|
+
> **iOS 15+ caveat — app pre-warming:** iOS can launch your process before first unlock for faster app startup. This means even `AfterFirstUnlock` items may be temporarily unavailable during pre-warm. Check `UIApplication.shared.isProtectedDataAvailable` before accessing keychain items, and defer if it returns `false`.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## The "How" Layer: SecAccessControl Flags
|
|
60
|
+
|
|
61
|
+
`SecAccessControl` adds runtime authentication requirements on top of data-at-rest protection. It is created via `SecAccessControlCreateWithFlags`, which embeds the accessibility level inside the control object:
|
|
62
|
+
|
|
63
|
+
```swift
|
|
64
|
+
func SecAccessControlCreateWithFlags(
|
|
65
|
+
_ allocator: CFAllocator?, // Pass nil
|
|
66
|
+
_ protection: CFTypeRef, // A kSecAttrAccessible constant
|
|
67
|
+
_ flags: SecAccessControlCreateFlags,
|
|
68
|
+
_ error: UnsafeMutablePointer<Unmanaged<CFError>?>?
|
|
69
|
+
) -> SecAccessControl?
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Available Flags
|
|
73
|
+
|
|
74
|
+
**Authentication constraints:**
|
|
75
|
+
|
|
76
|
+
- **`.userPresence`** (iOS 8+) — Biometry OR passcode. Does not require biometry enrollment; auto-falls back to passcode. Equivalent to `[.biometryAny, .or, .devicePasscode]` but handles no-biometry gracefully.
|
|
77
|
+
- **`.biometryAny`** (iOS 11.3+, was `.touchIDAny`) — Requires biometric authentication. Item **survives** enrollment changes (new fingerprints, Face ID re-enrollment).
|
|
78
|
+
- **`.biometryCurrentSet`** (iOS 11.3+, was `.touchIDCurrentSet`) — Requires biometric authentication. Item **invalidated** on enrollment changes. Most secure biometric option — blocks an attacker who enrolls their own biometrics.
|
|
79
|
+
- **`.devicePasscode`** (iOS 9+) — Requires device passcode entry only.
|
|
80
|
+
|
|
81
|
+
**Logical combinators:**
|
|
82
|
+
|
|
83
|
+
- **`.or`** — At least one constraint must be satisfied.
|
|
84
|
+
- **`.and`** — All constraints must be satisfied.
|
|
85
|
+
|
|
86
|
+
**Additional:**
|
|
87
|
+
|
|
88
|
+
- **`.privateKeyUsage`** (iOS 9+) — Required for Secure Enclave private key operations (signing, key agreement).
|
|
89
|
+
- **`.applicationPassword`** (iOS 9+) — Adds an app-provided password to key derivation. Not a constraint — an additional encryption layer.
|
|
90
|
+
|
|
91
|
+
### Flag Compatibility Matrix
|
|
92
|
+
|
|
93
|
+
| Flag | Works in Background? | Typical Pairing | Failure if Misused |
|
|
94
|
+
| ---------------------- | ------------------------ | ----------------------------------------- | -------------------------------------------- |
|
|
95
|
+
| `.userPresence` | No | Foreground + `WhenUnlocked` | `-25308` in background |
|
|
96
|
+
| `.biometryAny` | No | Foreground secrets | `errSecAuthFailed` if no biometrics enrolled |
|
|
97
|
+
| `.biometryCurrentSet` | No | `WhenPasscodeSetTDO` for highest security | Auth fails on enrollment change |
|
|
98
|
+
| `.devicePasscode` | No | Compliance flows | `-25308` without UI |
|
|
99
|
+
| `.privateKeyUsage` | Yes (for key ops) | Secure Enclave keys | — |
|
|
100
|
+
| `.applicationPassword` | Yes (if password cached) | Niche models | Password lifecycle management |
|
|
101
|
+
|
|
102
|
+
### Composing Constraints
|
|
103
|
+
|
|
104
|
+
Since `SecAccessControlCreateFlags` is an `OptionSet`, compose with array literal syntax:
|
|
105
|
+
|
|
106
|
+
```swift
|
|
107
|
+
// Biometry OR passcode — most common pattern
|
|
108
|
+
let flags: SecAccessControlCreateFlags = [.biometryCurrentSet, .or, .devicePasscode]
|
|
109
|
+
|
|
110
|
+
// Biometry AND passcode — both required (rare, high security)
|
|
111
|
+
let flags: SecAccessControlCreateFlags = [.biometryAny, .and, .devicePasscode]
|
|
112
|
+
|
|
113
|
+
// Biometry OR passcode, plus application password encryption
|
|
114
|
+
let flags: SecAccessControlCreateFlags = [.biometryAny, .or, .devicePasscode, .applicationPassword]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
> **Critical rule: `.or` / `.and` is required between authentication flags.** Combining `.biometryCurrentSet` and `.devicePasscode` without a logical operator causes `SecAccessControlCreateWithFlags` to return `nil` with `errSecParam` (-50). Both sources confirm this behavior.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## The Cardinal Rule: Never Set Both Attributes
|
|
122
|
+
|
|
123
|
+
`kSecAttrAccessible` and `kSecAttrAccessControl` are **mutually exclusive** in the query dictionary. When you use `SecAccessControlCreateWithFlags`, the accessibility level is embedded inside the `SecAccessControl` object via the `protection` parameter. Setting both in the same `SecItemAdd` query causes **`errSecParam` (-50)**.
|
|
124
|
+
|
|
125
|
+
```swift
|
|
126
|
+
// ❌ WRONG — sets accessibility twice, causes errSecParam (-50)
|
|
127
|
+
var error: Unmanaged<CFError>?
|
|
128
|
+
let access = SecAccessControlCreateWithFlags(
|
|
129
|
+
nil,
|
|
130
|
+
kSecAttrAccessibleWhenUnlockedThisDeviceOnly, // ← accessibility set HERE
|
|
131
|
+
[.biometryCurrentSet, .or, .devicePasscode],
|
|
132
|
+
&error
|
|
133
|
+
)!
|
|
134
|
+
|
|
135
|
+
let query: [String: Any] = [
|
|
136
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
137
|
+
kSecAttrAccount as String: "credential",
|
|
138
|
+
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly, // ❌ CONFLICT
|
|
139
|
+
kSecAttrAccessControl as String: access, // ← already contains accessibility
|
|
140
|
+
kSecValueData as String: secretData
|
|
141
|
+
]
|
|
142
|
+
// SecItemAdd returns errSecParam (-50)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
```swift
|
|
146
|
+
// ✅ CORRECT — accessibility set only inside SecAccessControl
|
|
147
|
+
var error: Unmanaged<CFError>?
|
|
148
|
+
guard let access = SecAccessControlCreateWithFlags(
|
|
149
|
+
nil,
|
|
150
|
+
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
|
|
151
|
+
[.biometryCurrentSet, .or, .devicePasscode],
|
|
152
|
+
&error
|
|
153
|
+
) else { throw KeychainError.accessControlCreationFailed(error?.takeRetainedValue()) }
|
|
154
|
+
|
|
155
|
+
let query: [String: Any] = [
|
|
156
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
157
|
+
kSecAttrAccount as String: "credential",
|
|
158
|
+
kSecAttrAccessControl as String: access, // Contains accessibility + auth flags
|
|
159
|
+
kSecValueData as String: secretData
|
|
160
|
+
]
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Decision Matrix: Choosing the Right Accessibility Level
|
|
166
|
+
|
|
167
|
+
### `WhenPasscodeSetThisDeviceOnly` — Data that should self-destruct
|
|
168
|
+
|
|
169
|
+
Use for your most sensitive credentials. Pair with `.biometryCurrentSet` via `SecAccessControl`. Accept the tradeoff: items are permanently destroyed on passcode removal and never survive device migration. Your app **must** handle item absence gracefully and guide users through re-authentication.
|
|
170
|
+
|
|
171
|
+
**Use cases:** Banking session tokens, password manager vault keys, healthcare credentials, E2E encryption private keys.
|
|
172
|
+
|
|
173
|
+
### `WhenUnlockedThisDeviceOnly` — Standard device-bound credentials
|
|
174
|
+
|
|
175
|
+
Credentials that should be device-bound but don't need passcode-deletion behavior. Re-authenticate after device migration.
|
|
176
|
+
|
|
177
|
+
**Use cases:** OAuth access tokens (refreshable), app-specific API keys, cached credentials, device registration tokens.
|
|
178
|
+
|
|
179
|
+
### `AfterFirstUnlockThisDeviceOnly` — Background operations (most common for services)
|
|
180
|
+
|
|
181
|
+
The correct choice for **any keychain item accessed by background code** — push notification handlers, WidgetKit timeline providers, background fetch, VPN extensions, notification service extensions. Device-bound.
|
|
182
|
+
|
|
183
|
+
**Use cases:** Push notification decryption keys, VPN credentials, background sync tokens, watch connectivity tokens.
|
|
184
|
+
|
|
185
|
+
### `AfterFirstUnlock` — Background + backup migration
|
|
186
|
+
|
|
187
|
+
Same background accessibility, plus items migrate with encrypted backups. Use when background access and device-transfer continuity are both needed.
|
|
188
|
+
|
|
189
|
+
**Use cases:** Enterprise VPN credentials, email account credentials, Wi-Fi configuration passwords.
|
|
190
|
+
|
|
191
|
+
### Dual-Item Strategy for Mixed Contexts
|
|
192
|
+
|
|
193
|
+
If a credential needs both background access (no UI) and foreground biometric protection (with UI), **store two separate items**: a background-capable token with `AfterFirstUnlockThisDeviceOnly` (no `SecAccessControl` user-presence flags) and a stronger foreground-only item with `WhenUnlockedThisDeviceOnly` + biometric `SecAccessControl`. This avoids the logical contradiction of biometric flags on background-accessible items.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Common AI-Generated Mistakes
|
|
198
|
+
|
|
199
|
+
### Mistake 1: Omitting `kSecAttrAccessible` (inheriting the wrong default)
|
|
200
|
+
|
|
201
|
+
The most pervasive error. AI code generators produce keychain wrappers that never set `kSecAttrAccessible`, inheriting `WhenUnlocked`. Works during development (device unlocked while testing), fails in production when background extensions execute while locked — `errSecInteractionNotAllowed` (-25308), often silently swallowed.
|
|
202
|
+
|
|
203
|
+
```swift
|
|
204
|
+
// ❌ WRONG — omits kSecAttrAccessible, defaults to WhenUnlocked
|
|
205
|
+
let query: [String: Any] = [
|
|
206
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
207
|
+
kSecAttrAccount as String: "authToken",
|
|
208
|
+
kSecAttrService as String: "com.example.app",
|
|
209
|
+
kSecValueData as String: tokenData
|
|
210
|
+
// Missing: kSecAttrAccessible — background extensions WILL fail with -25308
|
|
211
|
+
]
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
```swift
|
|
215
|
+
// ✅ CORRECT — explicit accessibility for background use
|
|
216
|
+
let query: [String: Any] = [
|
|
217
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
218
|
+
kSecAttrAccount as String: "authToken",
|
|
219
|
+
kSecAttrService as String: "com.example.app",
|
|
220
|
+
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
|
|
221
|
+
kSecValueData as String: tokenData
|
|
222
|
+
]
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Mistake 2: Using deprecated `kSecAttrAccessibleAlways`
|
|
226
|
+
|
|
227
|
+
Compiles with a warning on iOS 12+, runs at runtime — arguably worse than a hard failure. No meaningful lock-state protection.
|
|
228
|
+
|
|
229
|
+
```swift
|
|
230
|
+
// ❌ WRONG — deprecated since iOS 12
|
|
231
|
+
let query: [String: Any] = [
|
|
232
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
233
|
+
kSecAttrAccessible as String: kSecAttrAccessibleAlways, // ⚠️ Deprecated
|
|
234
|
+
kSecValueData as String: tokenData
|
|
235
|
+
]
|
|
236
|
+
// Replacement: kSecAttrAccessibleAfterFirstUnlock
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Mistake 3: Not handling `ThisDeviceOnly` item loss after device migration
|
|
240
|
+
|
|
241
|
+
Items with `ThisDeviceOnly` are cryptographically bound to the hardware UID. They are excluded from all backups, iCloud sync, and Quick Start device-to-device migration. After restoring to a new device, these items silently disappear — `errSecItemNotFound` (-25300). AI-generated code rarely implements re-authentication flows for this scenario.
|
|
242
|
+
|
|
243
|
+
### Mistake 4: Biometric flags on background-accessible protection levels
|
|
244
|
+
|
|
245
|
+
Setting `.biometryCurrentSet` with `kSecAttrAccessibleAfterFirstUnlock` is technically valid at the API level but creates a **logical contradiction**: `AfterFirstUnlock` implies background access while locked, but biometric auth requires an interactive prompt. Result: `errSecInteractionNotAllowed` in background contexts, defeating the purpose.
|
|
246
|
+
|
|
247
|
+
### Mistake 5: Conflicting flags without logical operator
|
|
248
|
+
|
|
249
|
+
Combining `.biometryCurrentSet` and `.devicePasscode` without `.or` or `.and` causes `SecAccessControlCreateWithFlags` to return `nil` / `errSecParam` (-50).
|
|
250
|
+
|
|
251
|
+
```swift
|
|
252
|
+
// ❌ WRONG — missing logical operator
|
|
253
|
+
let access = SecAccessControlCreateWithFlags(
|
|
254
|
+
nil,
|
|
255
|
+
kSecAttrAccessibleWhenUnlocked,
|
|
256
|
+
[.biometryCurrentSet, .devicePasscode], // Missing .or or .and
|
|
257
|
+
&error
|
|
258
|
+
)
|
|
259
|
+
// Returns nil, error contains errSecParam
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
```swift
|
|
263
|
+
// ✅ CORRECT — explicit .or between constraints
|
|
264
|
+
let access = SecAccessControlCreateWithFlags(
|
|
265
|
+
nil,
|
|
266
|
+
kSecAttrAccessibleWhenUnlocked,
|
|
267
|
+
[.biometryCurrentSet, .or, .devicePasscode],
|
|
268
|
+
&error
|
|
269
|
+
)
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Code Patterns
|
|
275
|
+
|
|
276
|
+
✅ The first two examples are correct patterns for foreground and background access. The third example is intentionally incorrect.
|
|
277
|
+
|
|
278
|
+
### Biometric protection with highest security
|
|
279
|
+
|
|
280
|
+
```swift
|
|
281
|
+
func saveBiometricProtectedItem(data: Data, account: String, service: String) throws {
|
|
282
|
+
var error: Unmanaged<CFError>?
|
|
283
|
+
guard let accessControl = SecAccessControlCreateWithFlags(
|
|
284
|
+
nil,
|
|
285
|
+
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
|
|
286
|
+
[.biometryCurrentSet, .or, .devicePasscode],
|
|
287
|
+
&error
|
|
288
|
+
) else {
|
|
289
|
+
throw KeychainError.accessControlCreationFailed(error?.takeRetainedValue())
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
let query: [String: Any] = [
|
|
293
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
294
|
+
kSecAttrAccount as String: account,
|
|
295
|
+
kSecAttrService as String: service,
|
|
296
|
+
kSecAttrAccessControl as String: accessControl,
|
|
297
|
+
kSecValueData as String: data
|
|
298
|
+
]
|
|
299
|
+
|
|
300
|
+
let status = SecItemAdd(query as CFDictionary, nil)
|
|
301
|
+
switch status {
|
|
302
|
+
case errSecSuccess: return
|
|
303
|
+
case errSecDuplicateItem:
|
|
304
|
+
// Must delete + re-add: SecItemUpdate cannot change SecAccessControl
|
|
305
|
+
let searchQuery: [String: Any] = [
|
|
306
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
307
|
+
kSecAttrAccount as String: account,
|
|
308
|
+
kSecAttrService as String: service
|
|
309
|
+
]
|
|
310
|
+
let deleteStatus = SecItemDelete(searchQuery as CFDictionary)
|
|
311
|
+
guard deleteStatus == errSecSuccess else {
|
|
312
|
+
throw KeychainError.fromStatus(deleteStatus)
|
|
313
|
+
}
|
|
314
|
+
let readdStatus = SecItemAdd(query as CFDictionary, nil)
|
|
315
|
+
guard readdStatus == errSecSuccess else {
|
|
316
|
+
throw KeychainError.fromStatus(readdStatus)
|
|
317
|
+
}
|
|
318
|
+
default:
|
|
319
|
+
throw KeychainError.fromStatus(status)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
> **Important:** `SecItemUpdate` **cannot** change a `SecAccessControl` attribute on an existing item. To change access control, you must delete and re-add. Both sources confirm this.
|
|
325
|
+
|
|
326
|
+
### Background-accessible token (push notifications, VPN, widgets)
|
|
327
|
+
|
|
328
|
+
```swift
|
|
329
|
+
func saveBackgroundToken(_ token: Data, account: String, service: String) throws {
|
|
330
|
+
let query: [String: Any] = [
|
|
331
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
332
|
+
kSecAttrAccount as String: account,
|
|
333
|
+
kSecAttrService as String: service,
|
|
334
|
+
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
|
|
335
|
+
kSecValueData as String: token
|
|
336
|
+
]
|
|
337
|
+
|
|
338
|
+
let status = SecItemAdd(query as CFDictionary, nil)
|
|
339
|
+
switch status {
|
|
340
|
+
case errSecSuccess: return
|
|
341
|
+
case errSecDuplicateItem:
|
|
342
|
+
let updateAttrs: [String: Any] = [kSecValueData as String: token]
|
|
343
|
+
let searchQuery: [String: Any] = [
|
|
344
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
345
|
+
kSecAttrAccount as String: account,
|
|
346
|
+
kSecAttrService as String: service
|
|
347
|
+
]
|
|
348
|
+
let updateStatus = SecItemUpdate(searchQuery as CFDictionary, updateAttrs as CFDictionary)
|
|
349
|
+
guard updateStatus == errSecSuccess else {
|
|
350
|
+
throw KeychainError.fromStatus(updateStatus)
|
|
351
|
+
}
|
|
352
|
+
default:
|
|
353
|
+
throw KeychainError.fromStatus(status)
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Accessing a `WhenUnlocked` item from a background extension
|
|
359
|
+
|
|
360
|
+
```swift
|
|
361
|
+
// Runs in WidgetKit TimelineProvider or NotificationServiceExtension while locked — WILL fail
|
|
362
|
+
func fetchTokenInBackground() -> String? {
|
|
363
|
+
let query: [String: Any] = [
|
|
364
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
365
|
+
kSecAttrAccount as String: "authToken",
|
|
366
|
+
kSecAttrService as String: "com.example.app",
|
|
367
|
+
kSecReturnData as String: true,
|
|
368
|
+
kSecMatchLimit as String: kSecMatchLimitOne
|
|
369
|
+
// Item stored with default WhenUnlocked — inaccessible while locked
|
|
370
|
+
]
|
|
371
|
+
|
|
372
|
+
var result: AnyObject?
|
|
373
|
+
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
374
|
+
// status == errSecInteractionNotAllowed (-25308) when device is locked
|
|
375
|
+
guard status == errSecSuccess, let data = result as? Data else {
|
|
376
|
+
return nil // ❌ Silent failure — no logging, no error propagation
|
|
377
|
+
}
|
|
378
|
+
return String(data: data, encoding: .utf8)
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## macOS: `kSecUseDataProtectionKeychain`
|
|
385
|
+
|
|
386
|
+
macOS has **two keychain implementations** (per TN3137): the legacy file-based keychain (`~/Library/Keychains/login.keychain-db`) and the modern Data Protection keychain. The `SecItem` API defaults to the **legacy** keychain on macOS.
|
|
387
|
+
|
|
388
|
+
Set `kSecUseDataProtectionKeychain: true` in every macOS keychain query to target the modern keychain. Without it:
|
|
389
|
+
|
|
390
|
+
- `SecAccessControl` flags fail with `errSecParam` (-50)
|
|
391
|
+
- iCloud Keychain sync doesn't work
|
|
392
|
+
- Secure Enclave integration is unavailable
|
|
393
|
+
- Biometric protection (Touch ID) won't function
|
|
394
|
+
|
|
395
|
+
```swift
|
|
396
|
+
// ✅ macOS: always include kSecUseDataProtectionKeychain
|
|
397
|
+
let query: [String: Any] = [
|
|
398
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
399
|
+
kSecAttrAccount as String: account,
|
|
400
|
+
kSecAttrService as String: service,
|
|
401
|
+
kSecUseDataProtectionKeychain as String: true, // ← Critical on macOS
|
|
402
|
+
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
|
|
403
|
+
kSecValueData as String: data
|
|
404
|
+
]
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
On iOS, tvOS, and watchOS, this flag is ignored (those platforms always use Data Protection). The Data Protection keychain requires a user login context — `launchd` daemons running outside a user session must use the legacy keychain. Mac Catalyst and iOS-on-Mac apps automatically use Data Protection.
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## NSFileProtection Sidebar
|
|
412
|
+
|
|
413
|
+
The keychain and file system share the same Data Protection architecture but expose it through different APIs. Use the keychain for small discrete secrets (passwords, tokens, keys). Use `NSFileProtection` for larger data (documents, databases, images).
|
|
414
|
+
|
|
415
|
+
**`NSFileProtectionComplete`** (Class A) = `kSecAttrAccessibleWhenUnlocked`. File inaccessible while locked. Class key discarded ~10 seconds after lock.
|
|
416
|
+
|
|
417
|
+
**`NSFileProtectionCompleteUnlessOpen`** (Class B) = **No keychain equivalent.** Uses asymmetric ECDH (Curve25519) to allow already-opened files to continue being written while locked. Designed for background downloads (e.g., mail attachment download continues writing to an already-open file).
|
|
418
|
+
|
|
419
|
+
**`NSFileProtectionCompleteUntilFirstUserAuthentication`** (Class C) = `kSecAttrAccessibleAfterFirstUnlock`. The default for third-party app files when no explicit protection is set. Available after first unlock.
|
|
420
|
+
|
|
421
|
+
**`NSFileProtectionNone`** (Class D) = deprecated `kSecAttrAccessibleAlways`. Protected only by device UID.
|
|
422
|
+
|
|
423
|
+
**Recommended layered approach:** Store encryption keys in the keychain with `WhenUnlockedThisDeviceOnly`, then use those keys to encrypt larger files on disk with `NSFileProtectionComplete` as an additional layer.
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## Error Codes Reference
|
|
428
|
+
|
|
429
|
+
| Code | Constant | Meaning | Common Root Cause |
|
|
430
|
+
| ---------- | ----------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
431
|
+
| **-25308** | `errSecInteractionNotAllowed` | Item not accessible in current state | Device locked + `WhenUnlocked` item; BFU state + `AfterFirstUnlock` item; biometric flag in background |
|
|
432
|
+
| **-50** | `errSecParam` | Invalid parameters | Both `kSecAttrAccessible` and `kSecAttrAccessControl` set; conflicting flags without `.or`/`.and`; missing `kSecUseDataProtectionKeychain` on macOS |
|
|
433
|
+
| **-25293** | `errSecAuthFailed` | Authentication failed | Biometric auth failed; enrollment changed with `.biometryCurrentSet`; no biometrics enrolled |
|
|
434
|
+
| **-25300** | `errSecItemNotFound` | Item not in keychain | Item never stored; `ThisDeviceOnly` lost after migration; `WhenPasscodeSet` deleted on passcode removal |
|
|
435
|
+
| **-25299** | `errSecDuplicateItem` | Item already exists | `SecItemAdd` when matching primary keys exist — use add-or-update pattern |
|
|
436
|
+
| **-128** | `errSecUserCanceled` | User canceled prompt | User tapped Cancel on biometric/passcode dialog |
|
|
437
|
+
| **-34018** | `errSecMissingEntitlement` | Missing entitlement | Keychain access group not in entitlements; common on iOS Simulator |
|
|
438
|
+
|
|
439
|
+
The most insidious is `-25308` — it surfaces in production but rarely during development because developers test with unlocked devices. Always handle it by deferring the operation and retrying when `UIApplication.shared.isProtectedDataAvailable` is `true`.
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## iOS Version Timeline
|
|
444
|
+
|
|
445
|
+
**iOS 8 (2014):** `WhenPasscodeSetThisDeviceOnly` introduced. `SecAccessControlCreateWithFlags` added. `.userPresence` flag.
|
|
446
|
+
|
|
447
|
+
**iOS 9 (2015):** `.devicePasscode`, `.applicationPassword`, `.privateKeyUsage` flags added. Apple announced intent to deprecate `Always` at WWDC 2015 Session 706.
|
|
448
|
+
|
|
449
|
+
**iOS 11.3 (2018):** `.touchIDAny` → `.biometryAny`; `.touchIDCurrentSet` → `.biometryCurrentSet` (unified naming for Face ID).
|
|
450
|
+
|
|
451
|
+
**iOS 12 (2018):** `kSecAttrAccessibleAlways` and `AlwaysThisDeviceOnly` formally deprecated. Both still compile and run for backward compatibility.
|
|
452
|
+
|
|
453
|
+
**iOS 15 (2021):** MDM-installed keychain items changed default from "always" to "after first unlock, nonmigratory." App pre-warming can launch processes before first unlock, making `AfterFirstUnlock` items temporarily unavailable.
|
|
454
|
+
|
|
455
|
+
**iOS 16 (2022):** Passkeys launched (FIDO2/WebAuthn key pairs synced via E2E encrypted iCloud Keychain). No changes to access control APIs.
|
|
456
|
+
|
|
457
|
+
**iOS 17 (2023):** Enterprise passkey support. No `kSecAttrAccessible` or `SecAccessControl` changes.
|
|
458
|
+
|
|
459
|
+
**iOS 18 (2024):** Standalone Passwords app. No keychain data protection API changes.
|
|
460
|
+
|
|
461
|
+
**iOS 26 (2025):** Stolen Device Protection enabled by default — requires biometric auth (no passcode fallback) for stored passwords when away from familiar locations. Secure passkey import/export via FIDO Alliance standard. No changes to `kSecAttrAccessible` constants.
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## Testing Requirements
|
|
466
|
+
|
|
467
|
+
All data protection testing **must** use physical devices with passcodes enabled. The iOS Simulator does not enforce `kSecAttrAccessible` or `NSFileProtection`, creating a false sense of security.
|
|
468
|
+
|
|
469
|
+
**Critical test scenarios:**
|
|
470
|
+
|
|
471
|
+
1. **Reboot / BFU state:** Reboot device, attempt keychain access before unlocking. `AfterFirstUnlock` items should return `-25308` or `-25300`. Unlock once, lock again, test background access — should succeed.
|
|
472
|
+
|
|
473
|
+
2. **Lock timing:** Store a `WhenUnlocked` item. Lock the device. Attempt read immediately — expect `-25308`.
|
|
474
|
+
|
|
475
|
+
3. **Passcode removal:** Store a `WhenPasscodeSetThisDeviceOnly` item. Remove passcode in Settings. Verify item is deleted (`-25300`).
|
|
476
|
+
|
|
477
|
+
4. **Biometric enrollment change:** Store an item with `.biometryCurrentSet`. Add a new fingerprint or Face ID appearance. Verify authentication fails (`-25293`).
|
|
478
|
+
|
|
479
|
+
5. **Backup/restore migration:** Back up device, restore to a different physical device. Verify all `ThisDeviceOnly` items are absent (`-25300`).
|
|
480
|
+
|
|
481
|
+
6. **Background extension access:** Trigger a notification service extension or widget timeline update while the device is locked. Verify `AfterFirstUnlock` items are readable and `WhenUnlocked` items are not.
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
## Cross-References
|
|
486
|
+
|
|
487
|
+
- `keychain-fundamentals.md` — SecItem CRUD patterns, add-or-update, OSStatus handling
|
|
488
|
+
- `biometric-authentication.md` — Biometric flag selection (`.biometryCurrentSet`, `.biometryAny`, `.userPresence`) and keychain-bound patterns
|
|
489
|
+
- `secure-enclave.md` — Hardware-backed keys with `SecAccessControl` and `.privateKeyUsage`
|
|
490
|
+
- `keychain-item-classes.md` — Class-specific accessibility considerations and primary key composition
|
|
491
|
+
- `common-anti-patterns.md` — Anti-pattern #5 (missing `kSecAttrAccessible`), #3 (LAContext-only gate)
|
|
492
|
+
- `compliance-owasp-mapping.md` — M9 (Insecure Data Storage) accessibility requirements
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## Summary Checklist
|
|
497
|
+
|
|
498
|
+
1. **Always set `kSecAttrAccessible` explicitly** — never rely on the `WhenUnlocked` default; choose the level matching your access context (foreground vs background)
|
|
499
|
+
2. **Never set both `kSecAttrAccessible` and `kSecAttrAccessControl`** in the same query dictionary — accessibility belongs inside `SecAccessControlCreateWithFlags`
|
|
500
|
+
3. **Use `AfterFirstUnlockThisDeviceOnly`** for any item accessed by background extensions, widgets, VPN, or push notification handlers
|
|
501
|
+
4. **Pair `WhenPasscodeSetThisDeviceOnly` with `.biometryCurrentSet`** for highest-security items, and handle item deletion on passcode removal gracefully
|
|
502
|
+
5. **Include `.or` or `.and`** when combining multiple authentication flags — omitting the operator causes `errSecParam` (-50)
|
|
503
|
+
6. **Set `kSecUseDataProtectionKeychain: true`** on all macOS keychain queries to target the modern Data Protection keychain
|
|
504
|
+
7. **Implement re-authentication flows** for `ThisDeviceOnly` items that will be absent after device migration or backup restore
|
|
505
|
+
8. **Check `isProtectedDataAvailable`** before keychain access in app launch paths — iOS 15+ pre-warming can start your process before first unlock
|
|
506
|
+
9. **Delete and re-add** (not update) when changing `SecAccessControl` on an existing item — `SecItemUpdate` cannot modify access control attributes
|
|
507
|
+
10. **Test on physical devices** across lock/unlock, reboot, passcode removal, and biometric enrollment change scenarios — the Simulator does not enforce data protection
|
|
508
|
+
11. **Block deprecated `kSecAttrAccessibleAlways` constants** in CI/CD linting and migrate existing items to `AfterFirstUnlock` on next foreground authentication
|