krz/keycask

Password manager: Swift core library, CLI for macOS/Linux/Windows, iOS/macOS app. cli password-manager swift

Commit f280f4008d

f280f4008d48c66d7309059b350a1cae54db51e4

parent: b255639dd5

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-18 01:25 UTC

Reject --length with --words

Layout: unified · split

Sources/keycask/Commands/Add.swift +3
@@ -28,6 +28,9 @@ struct PasswordOptions: ParsableArguments {
2828 if generate, words != nil {
2929 throw ValidationError("--generate and --words are mutually exclusive")
3030 }
31 if words != nil, length != nil {
32 throw ValidationError("--length and --words are mutually exclusive")
33 }
3134 if let length, length < 1 { throw ValidationError("--length must be at least 1") }
3235 if let words, words < 1 { throw ValidationError("--words must be at least 1") }
3336 if length != nil, !generate, words == nil {
Tests/KeycaskCLITests/AddShowTests.swift +13
@@ -101,6 +101,19 @@ import Testing
101101 #expect(r.stderr.contains("keycask init"))
102102 }
103103
104 @Test func lengthWithWordsIsUsageError() throws {
105 let cli = try CLI.initialized()
106 let r = try cli.run(["add", "a", "--words", "4", "--length", "30"])
107 #expect(r.status == 2)
108 }
109
110 @Test func addWithoutPasswordSourceIsUsageError() throws {
111 let cli = try CLI.initialized()
112 let r = try cli.run(["add", "x"], stdin: "")
113 #expect(r.status == 2)
114 #expect(r.stderr.contains("no password"))
115 }
116
104117 @Test func corruptVaultIsFailure() throws {
105118 let cli = try CLI.initialized()
106119 try Data("{}".utf8).write(to: cli.vault)