Description
Implement public struct GitHubCredentialStore: Sendable in GitHubIntegrationClient/GitHubCredentialStore.swift:
public func save(token: String, for login: String) throws(KeychainError)
public func load(for login: String) throws(KeychainError) -> String?
public func delete(for login: String) throws(KeychainError)
public func listAccounts() throws(KeychainError) -> [String]
public func currentAccount() -> String?
public func setCurrentAccount(_ login: String?)
Keychain attributes:
service = "com.relay.github"
account = <login> (GitHub username without @)
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
- Not synchronizable (no iCloud for dev tokens)
public enum KeychainError: Error, Equatable {
case osStatus(OSStatus)
case dataCorrupted
}
Current account pointer — in UserDefaults.standard under key com.relay.github.currentAccount. MVP is single active account; listAccounts() + setCurrentAccount prepare API for future multi-account UI.
Spec reference
See swarm-report/github-integration-decomposition.md#t-6.
Relationships
Acceptance criteria
Complexity
S
Suggested agent
developer-workflow:swift-engineer
Module / Layer
GitHubIntegrationClient / Storage
Description
Implement
public struct GitHubCredentialStore: SendableinGitHubIntegrationClient/GitHubCredentialStore.swift:Keychain attributes:
service = "com.relay.github"account = <login>(GitHub username without@)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnlyCurrent account pointer — in
UserDefaults.standardunder keycom.relay.github.currentAccount. MVP is single active account;listAccounts()+setCurrentAccountprepare API for future multi-account UI.Spec reference
See
swarm-report/github-integration-decomposition.md#t-6.Relationships
Acceptance criteria
save(token: "X", for: "alice")→load(for: "alice")returns"X"load(for: "alice")when nothing was ever saved → returnsnil, does NOT throwsave+delete(for: "alice")+load→nillistAccounts()returns all previously saved loginscurrentAccount()persists across process restarts (test with isolated UserDefaults suite)com.relay.github.test.<UUID>, cleanup intearDownswiftlint lint --strictpassesComplexity
S
Suggested agent
developer-workflow:swift-engineerModule / Layer
GitHubIntegrationClient/ Storage