square/Valet
Valet lets you securely store data in the iOS, tvOS, watchOS, or macOS Keychain without knowing a thing about how the Keychain works. It’s easy. We promise.
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 3w ago
- ✓12 active contributors
- ✓Apache-2.0 licensed
Show 3 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Concentrated ownership — top contributor handles 77% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/square/valet)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/square/valet on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: square/Valet
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/square/Valet shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 3w ago
- 12 active contributors
- Apache-2.0 licensed
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 77% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live square/Valet
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/square/Valet.
What it runs against: a local clone of square/Valet — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in square/Valet | Confirms the artifact applies here, not a fork |
| 2 | License is still Apache-2.0 | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | Last commit ≤ 52 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of square/Valet. If you don't
# have one yet, run these first:
#
# git clone https://github.com/square/Valet.git
# cd Valet
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of square/Valet and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "square/Valet(\\.git)?\\b" \\
&& ok "origin remote is square/Valet" \\
|| miss "origin remote is not square/Valet (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
&& ok "license is Apache-2.0" \\
|| miss "license drift — was Apache-2.0 at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 52 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~22d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/square/Valet"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Valet is a Swift/Objective-C wrapper around the iOS/macOS/tvOS/watchOS Keychain that eliminates the complexity of direct Keychain API usage. It provides a simple key-value interface (Valet.swift, Sources/Valet/) for securely storing passwords, tokens, and sensitive data without requiring developers to understand Keychain's SecItem queries, access control policies, or synchronization semantics. Layered architecture: Public API classes (Valet.swift, SecureEnclaveValet.swift, SinglePromptSecureEnclaveValet.swift) provide convenience; Internal/ contains low-level wrappers (Keychain.swift abstracts SecItem calls, Configuration.swift manages accessibility/service identifiers, SecItem.swift models query dictionaries); Accessibility.swift and CloudAccessibility.swift define when data is readable; Tests/ mirrors this structure with unit tests (ValetTests/) and integration tests (ValetIntegrationTests/) plus Objective-C bridge validation (ValetObjectiveCBridgeTests/).
👥Who it's for
iOS/macOS developers building apps that need to store secrets (API keys, user credentials, authentication tokens) securely. They want a drop-in replacement for UserDefaults that actually uses hardware-backed storage without wrestling with Security.framework boilerplate.
🌱Maturity & risk
Production-ready. The project shows strong maturity: 281KB of Swift code, comprehensive test suite across ValetIntegrationTests/, ValetTests/, and Objective-C bridge tests; CI/CD via GitHub Actions (.github/workflows/ci.yml, codeql.yml); Apache 2.0 licensed since v5.0.0; multiple platform targets (iOS, tvOS, watchOS, macOS) with official SPM support via Package.swift. Last visible activity shows active maintenance.
Low risk for core use cases, but consider: the library sits directly atop Security framework APIs (Sources/Valet/Internal/Keychain.swift wraps SecItem*), so iOS/macOS Keychain bugs or behavioral changes cascade down; single-vendor (Square) maintenance; Secure Enclave support (Sources/Valet/SecureEnclave.swift) requires iOS 9+ and specific hardware, creating complexity for older targets; migration logic (Sources/Valet/MigrationError.swift) suggests past Keychain-breaking changes.
Active areas of work
The repository appears actively maintained with CI automation (.github/workflows/ci.yml running on commits), code quality scanning (codeql.yml), and coverage tracking (Scripts/upload-coverage-reports.sh). No specific PR/milestone data visible, but the codebase has Swift Package Manager integration (Package.swift) and Objective-C interop (Valet.h bridging header, VAL*Tests.m test files) suggesting ongoing modernization alongside legacy support.
🚀Get running
git clone https://github.com/square/Valet.git
cd Valet
# For Swift Package Manager projects:
swift build
# For CocoaPods users:
sudo gem install cocoapods
pod install
# For Xcode development:
open Valet.xcodeproj
Daily commands:
Development build: swift build -c debug. Run tests: swift test or xcodebuild test -scheme Valet -destination 'platform=iOS Simulator,name=iPhone 15'. CocoaPods users: pod install && open Valet.xcworkspace. CI uses GitHub Actions workflows in .github/workflows/ running on each commit.
🗺️Map of the codebase
- Sources/Valet/Valet.swift: Main public API providing valet(with:accessibility:) factory, store(), string(), containsKey(), removeKey() methods that most users call directly
- Sources/Valet/Internal/Keychain.swift: Wraps all Security.framework SecItem* function calls (SecItemAdd, SecItemQuery, SecItemDelete); any Keychain operation routes through here
- Sources/Valet/Internal/Configuration.swift: Builds SecItem query dictionaries with accessibility settings, service identifiers, and Keychain attributes; controls when data is readable/writable
- Sources/Valet/Accessibility.swift: Defines .whenUnlocked, .afterFirstUnlock, .whenUnlockedThisDeviceOnly etc. enums; maps to SecAccessibilityAttr constants controlling Keychain data availability
- Sources/Valet/SecureEnclaveValet.swift: Extends Valet for hardware-backed keys on Secure Enclave; used for high-security credentials requiring biometric/pin access
- Tests/ValetIntegrationTests/KeychainIntegrationTests.swift: Tests actual Keychain behavior end-to-end; verifies store/retrieve/delete cycles hit real device Keychain, not mocks
- Sources/Valet/Internal/SecItem.swift: Models SecItem query dictionary structure; provides type-safe conversion between Swift enums and CFDictionary keys used by Security.framework
- Sources/Valet/Identifier.swift: Wrapper enforcing non-empty identifier strings at compile time; prevents invalid Valet initialization that would fail silently
🛠️How to make changes
Start here by use case: Adding new Keychain features: edit Sources/Valet/Internal/Keychain.swift (wraps SecItem* APIs), then expose via Sources/Valet/Valet.swift public API. Fixing accessibility bugs: modify Sources/Valet/Accessibility.swift enums or Sources/Valet/Internal/Configuration.swift. Extending Secure Enclave support: work in Sources/Valet/SecureEnclave.swift and SecureEnclaveValet.swift. Maintaining Objective-C bridge: edit Sources/Valet/Valet.h and corresponding Tests/ValetObjectiveCBridgeTests/VAL*.m files. Tests MUST be added in Tests/ValetIntegrationTests/ for real Keychain behavior.
🪤Traps & gotchas
No mocking in integration tests: ValetIntegrationTests/ runs against real Keychain, so tests are slow and require actual device/simulator; CI must be configured for simulator targets. Accessibility mismatches: Choosing .whenUnlockedThisDeviceOnly vs .whenUnlocked affects iCloud Keychain sync; wrong choice silently breaks CloudAccessibility use cases. Secure Enclave requires iOS 9+: SecureEnclaveValet.swift crashes on older targets; no runtime version check, must guard at call site. Identifier constraints: Identifier(nonEmpty:) returns optional; passing nil silently fails during initialization; common footgun in error handling paths. Shared group identifiers: SharedGroupIdentifier.swift enables app group Keychain sharing, but requires entitlement configuration that isn't validated by the library itself. Migration edge cases: MigrationError.swift suggests past data format breaks; legacy data may be unrecoverable if migration logic is skipped.
💡Concepts to learn
- Keychain (macOS/iOS Security.framework) — Valet is entirely a wrapper around Apple's Keychain; understanding Keychain semantics (access control lists, synchronization, deletion behavior) is critical when debugging failures or choosing Accessibility levels
- SecItem API (SecItemAdd, SecItemQuery, SecItemDelete) — Sources/Valet/Internal/Keychain.swift calls these low-level Security.framework functions; understanding their dictionary-based API and status codes helps troubleshoot Keychain errors
- SecAccessibilityAttr (kSecAttrAccessible) — Core to Valet's Accessibility.swift; controls when Keychain items are readable (when device locked, after first unlock, etc.) and whether they sync to iCloud; wrong choice breaks app behavior
- Hardware-backed keys and Secure Enclave — SecureEnclaveValet.swift leverages the Secure Enclave coprocessor (iOS 9+) to store keys that never leave the device and require biometric authentication; critical for high-security credential storage
- Accessibility Attributes and iCloud Keychain Sync — CloudAccessibility.swift vs Accessibility.swift: choosing kSecAttrAccessibleWhenUnlocked syncs to iCloud, kSecAttrAccessibleWhenUnlockedThisDeviceOnly does not; misunderstanding this silently breaks enterprise credential sharing
- Data serialization to/from Keychain (Data encoding) — Valet.swift methods like string(), data(), encode(Codable) must serialize Swift types to Data for Keychain storage (which stores binary CFData); deserialization failures cause silent data loss
- Service and Account identifiers (Keychain item attributes) — Sources/Valet/Internal/Service.swift and Configuration.swift construct kSecAttrService and kSecAttrAccount dictionary keys; these identify which items belong to your app's Keychain sandbox; collisions cause data overwrites
🔗Related repos
kishikawakatsumi/KeychainAccess— Alternative Swift Keychain wrapper with similar goals (simple API, no Security.framework boilerplate) but emphasizes iCloud sync and custom attributesFlight-School/SecureStorage— Focuses on encrypted local storage as Keychain alternative; useful for comparing approach (Valet uses native Keychain, SecureStorage uses encrypted files)square/certstrap— Companion cert/key management tool often used alongside Valet in Square's ecosystem for mutual TLS in secure applicationsapple/swift-crypto— Official Apple cryptographic primitives; some Valet users migrate to swift-crypto for custom encryption + Keychain storage of keysrealm/realm-swift— Complementary encrypted database for larger structured secrets; Valet handles small key-value (tokens, passwords), Realm handles encrypted collections
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive integration tests for SharedGroupIdentifier across multi-app scenarios
The repo has SharedGroupIdentifier.swift for app groups, but Tests/ValetIntegrationTests/ lacks dedicated tests for cross-app keychain sharing. This is critical for developers using app extensions or shared data scenarios. New contributors could add integration tests validating that data stored via one app with a shared group ID is accessible from another app using the same group.
- [ ] Create Tests/ValetIntegrationTests/SharedGroupIntegrationTests.swift
- [ ] Add test cases for storing and retrieving values across different bundle identifiers using the same SharedGroupIdentifier
- [ ] Verify migration scenarios work correctly with shared group keychain items
- [ ] Test error handling when shared group access is denied
- [ ] Update ci.yml if needed to support multi-target testing scenarios
Add macOS Secure Enclave tests to address platform gap in SecureEnclaveIntegrationTests.swift
Tests/ValetIntegrationTests/ has SecureEnclaveIntegrationTests.swift, but the file structure shows separate 'Valet iOS Test Host App' and 'Valet macOS Test Host App' directories. Secure Enclave is available on macOS 13.3+, but there are no dedicated macOS SE tests. This is a concrete testing gap that matters for macOS developers.
- [ ] Review SecureEnclaveIntegrationTests.swift to identify iOS-specific test cases
- [ ] Create Tests/ValetIntegrationTests/MacSecureEnclaveIntegrationTests.swift with macOS-specific variants
- [ ] Add availability checks for macOS 13.3+ where needed
- [ ] Ensure ci.yml runs these tests on appropriate macOS runners
- [ ] Test SecureEnclaveAccessControl behavior differences on macOS vs iOS
Add unit tests for MigratableKeyValuePair.swift and MigrationError.swift edge cases
Tests/ValetTests/ has individual test files for most modules, but MigratableKeyValuePair and MigrationError lack dedicated unit test files (only mentioned in file structure). These are critical for data migration scenarios. New contributors should add comprehensive tests covering serialization, version compatibility, and error states.
- [ ] Create Tests/ValetTests/MigratableKeyValuePairTests.swift covering: initialization, encoding/decoding, version validation
- [ ] Expand Tests/ValetTests/MigrationErrorTests.swift to cover all error cases: itemNotFound, unexpectedPasswordData, malformedInput, duplicateItem
- [ ] Add tests for migration from older Valet versions with different data formats
- [ ] Test edge cases: nil values, empty strings, maximum data sizes
- [ ] Add property-based tests using existing test utilities to ensure robustness
🌿Good first issues
- Add missing unit tests for Sources/Valet/Internal/Service.swift (visible in file list but no corresponding ServiceTests.swift in Tests/ValetTests/); implement tests for service name generation and keychain item grouping
- Expand SecureEnclaveValet integration test coverage in Tests/ValetIntegrationTests/SecureEnclaveIntegrationTests.swift to test failure modes when Secure Enclave is unavailable; currently only tests happy path
- Document the relationship between Accessibility.swift enum values and actual SecAccessibleAttr constants in comments; add examples showing which accessibility level is safe for each data type (passwords vs UI hints)
⭐Top contributors
Click to expand
Top contributors
- @dfed — 77 commits
- @dependabot[bot] — 7 commits
- @NickEntin — 3 commits
- @allisonmoyer — 3 commits
- @jshier — 2 commits
📝Recent commits
Click to expand
Recent commits
a69e31e— Bump addressable from 2.8.7 to 2.9.0 (#359) (dependabot[bot])b082dea— Bump activesupport from 7.2.1.2 to 7.2.3.1 (#356) (dependabot[bot])246baf6— Bump Valet to 5.1 (#354) (dfed)1f9952f— Allow explicitly set identifiers on all systems (#348) (antons)cf949b2— Fix Xcode 26.4: Duplicate typed throws API into @objc (#353) (jshier)1556f1c— Do not error CI when cocoapods.org 500s (#351) (dfed)922d317— Increase CI reliability by downloading iOS sim (#350) (dfed)6139be7— Create codeql.yml (#344) (dfed)58ad73e— Bump rexml from 3.3.9 to 3.4.2 (#347) (dependabot[bot])147bffd— Github Actions no longer supports older Xcodes and simulators well (#346) (dfed)
🔒Security observations
Valet demonstrates strong security posture as a cryptographic library. No critical vulnerabilities detected in the repository structure. The codebase follows security best practices by: (1) focusing entirely on secure storage without implementing crypto from scratch, (2) maintaining comprehensive test coverage including integration tests, (3) using GitHub Actions CI/CD with CodeQL static analysis, and (4) implementing platform-specific secure enclave support. The library appropriately delegates sensitive operations to OS-level APIs (iOS/macOS Keychain, SecureEnclave) rather than implementing custom cryptography. Minor recommendations include ensuring comprehensive security-focused test coverage and validating the Swift-Objective-C bridge security boundaries. No hardcoded secrets, exposed credentials, injection vulnerabilities, or infrastructure misconfigurations were identified in the provided file structure.
- Low · CodeQL Security Scanning Configuration —
.github/workflows/codeql.yml. While CodeQL is configured in .github/workflows/codeql.yml, the analysis cannot verify its strictness level or whether all security checks are enabled without reviewing the actual workflow file contents. Fix: Ensure CodeQL workflow is configured with appropriate severity levels and all relevant security queries are enabled. Review the workflow file to confirm it runs on all relevant triggers and branches. - Low · Test Coverage for Security-Critical Components —
Tests/ValetIntegrationTests/, Tests/ValetTests/. The codebase includes security-sensitive operations (Keychain access, SecureEnclave, credential storage) but the depth of security-specific test coverage cannot be determined from file structure alone. Fix: Ensure comprehensive test coverage for all Keychain operations, error handling paths, and edge cases in secure storage. Include tests for race conditions, memory handling, and secure data deletion. - Low · Objective-C Bridge Security —
Tests/ValetObjectiveCBridgeTests/. The presence of Objective-C bridge code (Tests/ValetObjectiveCBridgeTests/) suggests interoperability between Swift and Objective-C. This can introduce type safety issues if not properly validated. Fix: Ensure strict type checking at the Swift-Objective-C boundary. Use appropriate bridging headers and validate all data crossing the bridge. Consider deprecating Objective-C API in favor of pure Swift interfaces.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.