Skip to content

Commit 24ffc37

Browse files
Merge pull request #18 from omarzl/task/keychain-creation-log
Added new keychain path log
2 parents 778e10c + 6c3b211 commit 24ffc37

7 files changed

+217
-6
lines changed

MODULE.bazel.lock

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/SignHereLibrary/Commands/CreateKeychainCommand.swift

+48
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ internal struct CreateKeychainCommand: ParsableCommand {
2323
case unableToUnlockKeychain(keychainName: String, output: ShellOutput)
2424
case unableToUpdateKeychainLockTimeout(keychainName: String, output: ShellOutput)
2525
case unableToCreateKeychain(keychainName: String, output: ShellOutput)
26+
case unableToListKeychains(output: ShellOutput)
27+
case unableToFindKeychain(keychainName: String, output: ShellOutput)
2628

2729
var description: String {
2830
switch self {
@@ -47,6 +49,19 @@ internal struct CreateKeychainCommand: ParsableCommand {
4749
- Output: \(output.outputString)
4850
- Error: \(output.errorString)
4951
"""
52+
case let .unableToListKeychains(output: output):
53+
return """
54+
[CreateKeychainCommand] Unable to list keychains
55+
- Output: \(output.outputString)
56+
- Error: \(output.errorString)
57+
"""
58+
case let .unableToFindKeychain(keychainName: keychainName, output: output):
59+
return """
60+
[CreateKeychainCommand] Unable to find keychain
61+
- Keychain Name: \(keychainName)
62+
- Output: \(output.outputString)
63+
- Error: \(output.errorString)
64+
"""
5065
}
5166
}
5267
}
@@ -64,21 +79,25 @@ internal struct CreateKeychainCommand: ParsableCommand {
6479

6580
private let shell: Shell
6681
private let keychain: Keychain
82+
private let log: Log
6783

6884
internal init() {
6985
let shellImp: Shell = ShellImp()
7086
shell = shellImp
7187
keychain = KeychainImp(shell: shellImp, processInfo: ProcessInfoImp())
88+
log = LogImp()
7289
}
7390

7491
internal init(
7592
shell: Shell,
7693
keychain: Keychain,
94+
log: Log,
7795
keychainName: String,
7896
keychainPassword: String
7997
) {
8098
self.shell = shell
8199
self.keychain = keychain
100+
self.log = log
82101
self.keychainName = keychainName
83102
self.keychainPassword = keychainPassword
84103
}
@@ -89,6 +108,7 @@ internal struct CreateKeychainCommand: ParsableCommand {
89108
self.init(
90109
shell: shellImp,
91110
keychain: KeychainImp(shell: shellImp, processInfo: ProcessInfoImp()),
111+
log: LogImp(),
92112
keychainName: try container.decode(String.self, forKey: .keychainName),
93113
keychainPassword: try container.decode(String.self, forKey: .keychainPassword)
94114
)
@@ -104,6 +124,7 @@ internal struct CreateKeychainCommand: ParsableCommand {
104124
try keychain.setDefaultKeychain(keychainName: keychainName)
105125
try updateKeychainLockTimeout()
106126
try unlockKeychain()
127+
try logKeychainPath()
107128
}
108129

109130
private func createKeychain() throws {
@@ -157,4 +178,31 @@ internal struct CreateKeychainCommand: ParsableCommand {
157178
)
158179
}
159180
}
181+
182+
private func logKeychainPath() throws {
183+
let output: ShellOutput = shell.execute([
184+
"security",
185+
"list-keychains"
186+
])
187+
guard output.isSuccessful
188+
else {
189+
throw Error.unableToListKeychains(
190+
output: output
191+
)
192+
}
193+
guard let keychainLine = output
194+
.outputString
195+
.components(separatedBy: "\n")
196+
.first(where: { $0.contains(keychainName) })
197+
else {
198+
throw Error.unableToFindKeychain(
199+
keychainName: keychainName,
200+
output: output
201+
)
202+
}
203+
let keychainPath = keychainLine
204+
.trimmingCharacters(in: .whitespacesAndNewlines)
205+
.replacingOccurrences(of:"\"", with: "")
206+
log.append("Keychain created in the path: \(keychainPath)")
207+
}
160208
}

Tests/SignHereLibraryTests/CreateKeychainCommandTests.swift

+81-3
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@ import XCTest
1616
final class CreateKeychainCommandTests: XCTestCase {
1717
var shell: ShellMock!
1818
var keychain: KeychainMock!
19+
var log: LogMock!
1920
var subject: CreateKeychainCommand!
2021

2122
override func setUp() {
2223
super.setUp()
2324
shell = .init()
2425
keychain = .init()
26+
log = .init()
2527
subject = .init(
2628
shell: shell,
2729
keychain: keychain,
30+
log: log,
2831
keychainName: "keychainName",
2932
keychainPassword: "keychainPassword"
3033
)
@@ -33,6 +36,7 @@ final class CreateKeychainCommandTests: XCTestCase {
3336
override func tearDown() {
3437
shell = nil
3538
keychain = nil
39+
log = nil
3640
subject = nil
3741
super.tearDown()
3842
}
@@ -69,6 +73,21 @@ final class CreateKeychainCommandTests: XCTestCase {
6973
).description,
7074
as: .lines
7175
)
76+
77+
assertSnapshot(
78+
matching: CreateKeychainCommand.Error.unableToListKeychains(
79+
output: .init(status: 0, data: .init("output".utf8), errorData: .init("errorOutput".utf8))
80+
).description,
81+
as: .lines
82+
)
83+
84+
assertSnapshot(
85+
matching: CreateKeychainCommand.Error.unableToFindKeychain(
86+
keychainName: "keychainName",
87+
output: .init(status: 0, data: .init("output".utf8), errorData: .init("errorOutput".utf8))
88+
).description,
89+
as: .lines
90+
)
7291
}
7392

7493
func test_initDecoder() throws {
@@ -92,7 +111,8 @@ final class CreateKeychainCommandTests: XCTestCase {
92111
var executeLaunchPaths: [ShellOutput] = [
93112
.init(status: 1, data: .init("createKeychain".utf8), errorData: .init()),
94113
.init(status: 0, data: .init("updateKeychainLockTimeout".utf8), errorData: .init()),
95-
.init(status: 0, data: .init("unlockKeychain".utf8), errorData: .init())
114+
.init(status: 0, data: .init("unlockKeychain".utf8), errorData: .init()),
115+
.init(status: 0, data: .init("listKeychain".utf8), errorData: .init())
96116
]
97117
shell.executeLaunchPathHandler = { _, _, _, _ in
98118
executeLaunchPaths.removeFirst()
@@ -119,7 +139,8 @@ final class CreateKeychainCommandTests: XCTestCase {
119139
var executeLaunchPaths: [ShellOutput] = [
120140
.init(status: 0, data: .init("createKeychain".utf8), errorData: .init()),
121141
.init(status: 1, data: .init("updateKeychainLockTimeout".utf8), errorData: .init()),
122-
.init(status: 0, data: .init("unlockKeychain".utf8), errorData: .init())
142+
.init(status: 0, data: .init("unlockKeychain".utf8), errorData: .init()),
143+
.init(status: 0, data: .init("listKeychain".utf8), errorData: .init())
123144
]
124145
shell.executeLaunchPathHandler = { _, _, _, _ in
125146
executeLaunchPaths.removeFirst()
@@ -146,7 +167,8 @@ final class CreateKeychainCommandTests: XCTestCase {
146167
var executeLaunchPaths: [ShellOutput] = [
147168
.init(status: 0, data: .init("createKeychain".utf8), errorData: .init()),
148169
.init(status: 0, data: .init("updateKeychainLockTimeout".utf8), errorData: .init()),
149-
.init(status: 1, data: .init("unlockKeychain".utf8), errorData: .init())
170+
.init(status: 1, data: .init("unlockKeychain".utf8), errorData: .init()),
171+
.init(status: 0, data: .init("listKeychain".utf8), errorData: .init()),
150172
]
151173
shell.executeLaunchPathHandler = { _, _, _, _ in
152174
executeLaunchPaths.removeFirst()
@@ -167,4 +189,60 @@ final class CreateKeychainCommandTests: XCTestCase {
167189
as: .dump
168190
)
169191
}
192+
193+
func test_execute_cannotListKeychain() throws {
194+
// GIVEN
195+
var executeLaunchPaths: [ShellOutput] = [
196+
.init(status: 0, data: .init("createKeychain".utf8), errorData: .init()),
197+
.init(status: 0, data: .init("updateKeychainLockTimeout".utf8), errorData: .init()),
198+
.init(status: 0, data: .init("unlockKeychain".utf8), errorData: .init()),
199+
.init(status: 1, data: .init("listKeychain".utf8), errorData: .init()),
200+
]
201+
shell.executeLaunchPathHandler = { _, _, _, _ in
202+
executeLaunchPaths.removeFirst()
203+
}
204+
205+
// WHEN
206+
XCTAssertThrowsError(try subject.run()) {
207+
if case CreateKeychainCommand.Error.unableToListKeychains(output: _) = $0 {
208+
XCTAssertTrue(true)
209+
} else {
210+
XCTFail($0.localizedDescription)
211+
}
212+
}
213+
214+
// THEN
215+
assertSnapshot(
216+
matching: shell.executeLaunchPathArgValues,
217+
as: .dump
218+
)
219+
}
220+
221+
func test_execute_cannotFindKeychain() throws {
222+
// GIVEN
223+
var executeLaunchPaths: [ShellOutput] = [
224+
.init(status: 0, data: .init("createKeychain".utf8), errorData: .init()),
225+
.init(status: 0, data: .init("updateKeychainLockTimeout".utf8), errorData: .init()),
226+
.init(status: 0, data: .init("unlockKeychain".utf8), errorData: .init()),
227+
.init(status: 0, data: .init("listKeychain".utf8), errorData: .init()),
228+
]
229+
shell.executeLaunchPathHandler = { _, _, _, _ in
230+
executeLaunchPaths.removeFirst()
231+
}
232+
233+
// WHEN
234+
XCTAssertThrowsError(try subject.run()) {
235+
if case CreateKeychainCommand.Error.unableToFindKeychain(keychainName: _, output: _) = $0 {
236+
XCTAssertTrue(true)
237+
} else {
238+
XCTFail($0.localizedDescription)
239+
}
240+
}
241+
242+
// THEN
243+
assertSnapshot(
244+
matching: shell.executeLaunchPathArgValues,
245+
as: .dump
246+
)
247+
}
170248
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[CreateKeychainCommand] Unable to list keychains
2+
- Output: output
3+
- Error: errorOutput
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[CreateKeychainCommand] Unable to find keychain
2+
- Keychain Name: keychainName
3+
- Output: output
4+
- Error: errorOutput
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
▿ 4 elements
2+
▿ (4 elements)
3+
- .0: "/usr/bin/env"
4+
▿ .1: 5 elements
5+
- "security"
6+
- "create-keychain"
7+
- "-p"
8+
- "keychainPassword"
9+
- "keychainName"
10+
- .2: Optional<Dictionary<String, String>>.none
11+
- .3: Optional<Data>.none
12+
▿ (4 elements)
13+
- .0: "/usr/bin/env"
14+
▿ .1: 6 elements
15+
- "security"
16+
- "set-keychain-settings"
17+
- "-t"
18+
- "7200"
19+
- "-l"
20+
- "keychainName"
21+
- .2: Optional<Dictionary<String, String>>.none
22+
- .3: Optional<Data>.none
23+
▿ (4 elements)
24+
- .0: "/usr/bin/env"
25+
▿ .1: 5 elements
26+
- "security"
27+
- "unlock-keychain"
28+
- "-p"
29+
- "keychainPassword"
30+
- "keychainName"
31+
- .2: Optional<Dictionary<String, String>>.none
32+
- .3: Optional<Data>.none
33+
▿ (4 elements)
34+
- .0: "/usr/bin/env"
35+
▿ .1: 2 elements
36+
- "security"
37+
- "list-keychains"
38+
- .2: Optional<Dictionary<String, String>>.none
39+
- .3: Optional<Data>.none
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
▿ 4 elements
2+
▿ (4 elements)
3+
- .0: "/usr/bin/env"
4+
▿ .1: 5 elements
5+
- "security"
6+
- "create-keychain"
7+
- "-p"
8+
- "keychainPassword"
9+
- "keychainName"
10+
- .2: Optional<Dictionary<String, String>>.none
11+
- .3: Optional<Data>.none
12+
▿ (4 elements)
13+
- .0: "/usr/bin/env"
14+
▿ .1: 6 elements
15+
- "security"
16+
- "set-keychain-settings"
17+
- "-t"
18+
- "7200"
19+
- "-l"
20+
- "keychainName"
21+
- .2: Optional<Dictionary<String, String>>.none
22+
- .3: Optional<Data>.none
23+
▿ (4 elements)
24+
- .0: "/usr/bin/env"
25+
▿ .1: 5 elements
26+
- "security"
27+
- "unlock-keychain"
28+
- "-p"
29+
- "keychainPassword"
30+
- "keychainName"
31+
- .2: Optional<Dictionary<String, String>>.none
32+
- .3: Optional<Data>.none
33+
▿ (4 elements)
34+
- .0: "/usr/bin/env"
35+
▿ .1: 2 elements
36+
- "security"
37+
- "list-keychains"
38+
- .2: Optional<Dictionary<String, String>>.none
39+
- .3: Optional<Data>.none

0 commit comments

Comments
 (0)