Skip to content

Commit 13ea3fc

Browse files
committed
v0.51.0 — Test Coverage Expansion
Testing: - internal/skills/llm_enhance_test.go — 17 new tests: parseLLMSuggestion (8 cases), GenerateSkillWithLLM (6 cases), EnhanceCurationWithLLM (5 cases) - internal/skills/scored_matcher_test.go — 20 new tests: NewScoredMatcher defaults, MatchSkills edge cases, scoreSkill, ExplainMatch, config defaults - internal/skills/notifier_test.go — 9 tests: NoopNotifier, MultiNotifier fan-out - internal/danger/approver_test.go — +7 tests: SetTrustAll, non-interactive deny - internal/telegram/health_test.go — 6 tests: SetLogger, SetReady, Start/shutdown Infrastructure: - health.go: store actual bound address after net.Listen for :0 port tests Coverage gains: GenerateSkillWithLLM 5%→92%, NewScoredMatcher 64%→100%, health/loggers 0%→100%, notifier 0%→100%, SetTrustAll 0%→100%
1 parent 5394ea0 commit 13ea3fc

7 files changed

Lines changed: 950 additions & 211 deletions

File tree

docs/CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
# Changelog
22

3+
## v0.51.0 (2026-05-25) — Test Coverage Expansion
4+
5+
### Testing
6+
- **`internal/skills/llm_enhance_test.go`** — 17 new tests covering `parseLLMSuggestion` (8 cases: valid, missing name/body, empty input, whitespace, multiline), `GenerateSkillWithLLM` (6 cases: nil LLM, LLM error, empty response, success, tool calls, truncation), and `EnhanceCurationWithLLM` (5 cases: nil LLM, nil report, empty report, LLM failure, success)
7+
- **`internal/skills/scored_matcher_test.go`** — 20 new tests covering `NewScoredMatcher` config defaults, `MatchSkills` (nil receiver, empty, exact, action, description, sorting, capping, no match, deterministic order), `scoreSkill` (topic, action, no match), `ExplainMatch` format, and config default validation
8+
- **`internal/skills/notifier_test.go`** — 9 new tests covering `NoopNotifier`, `NewMultiNotifier` (zero/one/multiple), fan-out dispatch and event independence
9+
- **`internal/danger/approver_test.go`** — 7 new tests covering `SetTrustAll` (enable/disable), `PromptCommand` non-interactive deny, trusted class bypass
10+
- **`internal/telegram/health_test.go`** — 6 new tests covering `NewHealthServer`, `SetLogger`, `SetReady`, `Start`/shutdown with live HTTP check, `ServeHTTP`
11+
- **Coverage improved**: `GenerateSkillWithLLM` 5%→92%, `NewScoredMatcher` 64%→100%, health `SetLogger`/`SetReady` 0%→100%, notifier `Notify` 0%→100%, `SetTrustAll` 0%→100%
12+
13+
### Infrastructure
14+
- **`internal/telegram/health.go`** — store actual bound address after `net.Listen` so tests using `:0` can discover the port
15+
16+
## v0.50.0 (2026-05-25) — Module Rename: kode → odek
17+
18+
### Breaking Changes
19+
- **Module path renamed** from `github.com/BackendStack21/kode` to `github.com/BackendStack21/odek` — all imports updated
20+
321
## v0.49.2 (2026-05-25) — Prompt Trimming & Web UI Context
422

523
### Intelligence Improvements

internal/danger/approver_test.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,128 @@ func TestPromptOperation_NoTTY_Allow(t *testing.T) {
152152
t.Errorf("expected nil for non-interactive allow, got: %v", err)
153153
}
154154
}
155+
156+
func TestSetTrustAll_ApprovesAll(t *testing.T) {
157+
a := NewTTYApprover(&DangerousConfig{NonInteractive: strPtr("deny")})
158+
a.TTYPath = "/nonexistent/tty-for-test"
159+
160+
// Enable blanket trust
161+
a.SetTrustAll(true)
162+
163+
// Destructive class should auto-approve despite NonInteractive=deny
164+
if err := a.PromptCommand(Destructive, "rm -rf /", "dangerous command"); err != nil {
165+
t.Errorf("expected nil with trustAll=true, got: %v", err)
166+
}
167+
168+
// Blocked class should also auto-approve
169+
if err := a.PromptCommand(Blocked, "some blocked cmd", ""); err != nil {
170+
t.Errorf("expected nil with trustAll=true, got: %v", err)
171+
}
172+
}
173+
174+
func TestSetTrustAll_ThenDisable(t *testing.T) {
175+
a := NewTTYApprover(&DangerousConfig{NonInteractive: strPtr("deny")})
176+
a.TTYPath = "/nonexistent/tty-for-test"
177+
178+
// Enable blanket trust
179+
a.SetTrustAll(true)
180+
181+
// Should be approved
182+
if err := a.PromptCommand(Destructive, "rm -rf /", ""); err != nil {
183+
t.Errorf("expected nil with trustAll=true, got: %v", err)
184+
}
185+
186+
// Disable blanket trust
187+
a.SetTrustAll(false)
188+
189+
// Should now be denied (no TTY, NonInteractive=deny)
190+
err := a.PromptCommand(Destructive, "rm -rf /", "")
191+
if err == nil {
192+
t.Fatal("expected error after disabling trustAll")
193+
}
194+
if !strings.Contains(err.Error(), "denied") {
195+
t.Errorf("expected 'denied' in error message, got: %v", err)
196+
}
197+
}
198+
199+
func TestPromptCommand_NoTTY_NilConfigDefaultAllow(t *testing.T) {
200+
a := NewTTYApprover(nil)
201+
a.TTYPath = "/nonexistent/tty-for-test"
202+
203+
// Nil config with no TTY → NonInteractive defaults to Allow → returns nil
204+
err := a.PromptCommand(SystemWrite, "some command", "")
205+
if err != nil {
206+
t.Errorf("expected nil for nil config + no TTY, got: %v", err)
207+
}
208+
}
209+
210+
func TestPromptCommand_NoTTY_NonInteractiveDeny_Untrusted(t *testing.T) {
211+
a := NewTTYApprover(&DangerousConfig{NonInteractive: strPtr("deny")})
212+
a.TTYPath = "/nonexistent/tty-for-test"
213+
214+
// No trusted classes configure, non-interactive deny → should error
215+
err := a.PromptCommand(SystemWrite, "touch /etc/config", "write system file")
216+
if err == nil {
217+
t.Fatal("expected error for non-interactive deny with no TTY")
218+
}
219+
if !strings.Contains(err.Error(), "denied") {
220+
t.Errorf("expected 'denied' in error message, got: %v", err)
221+
}
222+
}
223+
224+
func TestPromptCommand_TrustedClassSkipsTTY(t *testing.T) {
225+
a := NewTTYApprover(&DangerousConfig{NonInteractive: strPtr("deny")})
226+
a.TTYPath = "/nonexistent/tty-for-test"
227+
228+
// Trust Destructive class
229+
a.SetTrustedClasses(map[RiskClass]bool{Destructive: true})
230+
231+
// Trusted class is checked before TTY → should succeed even with NonInteractive=deny
232+
err := a.PromptCommand(Destructive, "rm -rf /tmp/data", "")
233+
if err != nil {
234+
t.Errorf("expected nil for trusted class, got: %v", err)
235+
}
236+
237+
// SystemWrite is NOT trusted → should be denied
238+
err = a.PromptCommand(SystemWrite, "touch /etc/config", "")
239+
if err == nil {
240+
t.Fatal("expected error for untrusted class with NonInteractive=deny")
241+
}
242+
if !strings.Contains(err.Error(), "denied") {
243+
t.Errorf("expected 'denied' in error message, got: %v", err)
244+
}
245+
}
246+
247+
func TestPromptOperation_NoTTY_NonInteractiveDeny(t *testing.T) {
248+
a := NewTTYApprover(&DangerousConfig{NonInteractive: strPtr("deny")})
249+
a.TTYPath = "/nonexistent/tty-for-test"
250+
251+
op := ToolOperation{
252+
Name: "write_file",
253+
Resource: "/etc/system/config",
254+
Risk: SystemWrite,
255+
}
256+
err := a.PromptOperation(op)
257+
if err == nil {
258+
t.Fatal("expected error for non-interactive deny with no TTY")
259+
}
260+
if !strings.Contains(err.Error(), "denied") {
261+
t.Errorf("expected 'denied' in error message, got: %v", err)
262+
}
263+
}
264+
265+
func TestPromptCommand_NoTTY_NonInteractiveDeny_SafeClass(t *testing.T) {
266+
a := NewTTYApprover(&DangerousConfig{NonInteractive: strPtr("deny")})
267+
a.TTYPath = "/nonexistent/tty-for-test"
268+
269+
// Safe class is not in trusted classes but no trusted classes configured at all
270+
// so TrustedClasses map exists but is empty → Safe is not trusted
271+
// NonInteractive=deny + no TTY → should error
272+
err := a.PromptCommand(Safe, "ls", "")
273+
if err == nil {
274+
t.Fatal("expected error for non-interactive deny with no TTY")
275+
}
276+
if !strings.Contains(err.Error(), "denied") {
277+
t.Errorf("expected 'denied' in error message, got: %v", err)
278+
}
279+
}

0 commit comments

Comments
 (0)