nightshift: test-gap — Test Coverage Gap Analysis
Repo: Microck/tailstick
Language: Go 1.25.6
Analyzed: 2026-04-30
Summary
Tailstick has 6 test files covering 5 packages with ~30 test functions. However, 5 source files (2,432 lines, 38% of the codebase) have zero test coverage. Critical gaps exist in state persistence, platform detection, CLI command dispatch, and logging.
Coverage Map
| Package |
Source File |
Lines |
Test File |
Status |
| app |
workflow.go |
755 |
workflow_test.go ✅ |
15 tests — good |
| tailscale |
client.go |
270 |
client_test.go ✅ |
7 tests — good |
| gui |
server.go |
247 |
server_test.go ✅ |
4 tests — good |
| config |
config.go |
116 |
config_test.go ✅ |
1 test — minimal |
| crypto |
secret.go |
128 |
secret_test.go ✅ |
2 tests — adequate |
| state |
store.go |
82 |
❌ None |
0 tests |
| platform |
platform.go |
175 |
❌ None |
0 tests |
| platform |
exec.go |
41 |
❌ None |
0 tests |
| app |
cli.go |
196 |
❌ None |
0 tests |
| logging |
logger.go |
63 |
❌ None |
0 tests |
| model |
types.go |
133 |
N/A (types only) |
Low priority |
Coverage Statistics
- Files with tests: 5 / 11 source files (45%)
- Lines with tests: ~1,516 / ~2,432 (62% by line count)
- Untested lines: 557 across 5 files
Priority Gaps
🔴 HIGH — internal/state/store.go (82 lines, 0 tests)
Functions untested:
Load(path string) — reads JSON state file, handles missing/corrupt files
Save(path string, state LocalState) — writes state file, creates parent dirs
UpsertRecord(state LocalState, rec LeaseRecord) — merges lease records
AppendAudit(path string, entry AuditEntry) — appends NDJSON audit entries
Why critical: State persistence is the core of lease management. A bug in UpsertRecord could silently lose lease records, causing orphaned Tailscale devices. AppendAudit failures could lose audit trails required for compliance.
Recommended tests:
TestLoadReturnsDefaultOnMissingFile
TestLoadReturnsErrorOnCorruptJSON
TestSaveCreatesParentDirectories
TestUpsertRecordAddsNewRecord
TestUpsertRecordUpdatesExistingByID
TestAppendAuditCreatesFileIfMissing
TestAppendAuditAppendsToExistingFile
🔴 HIGH — internal/platform/platform.go (175 lines, 0 tests)
Functions untested:
Detect() — detects OS, hostname, boot ID for lease tracking
IsLinux(), IsWindows() — platform checks
StatePath(), LogPath(), LocalSecretPath(), AgentBinaryPath() — path resolution
RequireSupportedLinux() — validates distro support
IsElevated() — privilege check
ElevationHint(exePath, args) — generates sudo/runas messages
sanitizeHost(in string) — hostname sanitization
Why critical: Platform detection errors could cause leases to run with wrong paths or fail privilege checks. sanitizeHost is a security-sensitive input sanitization function.
Recommended tests:
TestSanitizeHostStripsSpecialChars
TestDetectSetsCorrectOS
TestStatePathPlatformSpecific
TestIsElevatedCurrentContext
TestRequireSupportedLinuxRejectsUnknownDistro
🟡 MEDIUM — internal/app/cli.go (196 lines, 0 tests)
Functions untested:
RunCLI(args, Runtime) — main CLI dispatch (routes to run/agent/cleanup/version)
runEnroll(args, Runtime) — enrollment flow parsing
runAgent(args, Runtime) — agent mode parsing
runCleanup(args, Runtime) — cleanup flow parsing
interruptContext() — signal handling
printHelp() — help output
Why important: CLI dispatch is the user-facing entry point. Flag parsing bugs here surface as confusing errors. The interruptContext function handles graceful shutdown.
Recommended tests:
TestRunCLIDispatchesRunCommand
TestRunCLIDispatchesAgentCommand
TestRunCLIDispatchesCleanupCommand
TestRunCLIUnknownCommandReturnsError
TestRunCLIPrintsHelp
🟡 MEDIUM — internal/platform/exec.go (41 lines, 0 tests)
Functions untested:
Runner.Run(ctx, args) — executes commands with context cancellation
Runner.RunWithTimeout(timeout, args) — timeout-wrapped execution
Why important: Command execution is security-sensitive. These wrap os/exec calls that run Tailscale commands on the system. Context cancellation and timeout behavior should be verified.
Recommended tests:
TestRunnerRunExecutesCommand
TestRunnerRunRespectsContextCancellation
TestRunnerRunWithTimeoutExpires
🟢 LOW — internal/logging/logger.go (63 lines, 0 tests)
Functions untested:
New(path) — creates log file
Info/Error — formatted logging
Close() — file cleanup
Why low: Logging is non-critical. Failures here don't affect lease correctness.
Existing Test Quality Notes
config_test.go has only 1 test — should cover more config loading scenarios (missing fields, invalid JSON, env var precedence)
crypto/secret_test.go covers encrypt/decrypt but not edge cases (empty password, very long passwords, key file permission errors)
Recommended Priority Order
- state/store.go — highest impact, data integrity
- platform/platform.go — security-sensitive input handling
- app/cli.go — user-facing correctness
- platform/exec.go — execution safety
- logging/logger.go — nice to have
Generated by nightshift — test-gap analysis
nightshift: test-gap — Test Coverage Gap Analysis
Repo: Microck/tailstick
Language: Go 1.25.6
Analyzed: 2026-04-30
Summary
Tailstick has 6 test files covering 5 packages with ~30 test functions. However, 5 source files (2,432 lines, 38% of the codebase) have zero test coverage. Critical gaps exist in state persistence, platform detection, CLI command dispatch, and logging.
Coverage Map
workflow.goworkflow_test.go✅client.goclient_test.go✅server.goserver_test.go✅config.goconfig_test.go✅secret.gosecret_test.go✅store.goplatform.goexec.gocli.gologger.gotypes.goCoverage Statistics
Priority Gaps
🔴 HIGH —
internal/state/store.go(82 lines, 0 tests)Functions untested:
Load(path string)— reads JSON state file, handles missing/corrupt filesSave(path string, state LocalState)— writes state file, creates parent dirsUpsertRecord(state LocalState, rec LeaseRecord)— merges lease recordsAppendAudit(path string, entry AuditEntry)— appends NDJSON audit entriesWhy critical: State persistence is the core of lease management. A bug in
UpsertRecordcould silently lose lease records, causing orphaned Tailscale devices.AppendAuditfailures could lose audit trails required for compliance.Recommended tests:
TestLoadReturnsDefaultOnMissingFileTestLoadReturnsErrorOnCorruptJSONTestSaveCreatesParentDirectoriesTestUpsertRecordAddsNewRecordTestUpsertRecordUpdatesExistingByIDTestAppendAuditCreatesFileIfMissingTestAppendAuditAppendsToExistingFile🔴 HIGH —
internal/platform/platform.go(175 lines, 0 tests)Functions untested:
Detect()— detects OS, hostname, boot ID for lease trackingIsLinux(),IsWindows()— platform checksStatePath(),LogPath(),LocalSecretPath(),AgentBinaryPath()— path resolutionRequireSupportedLinux()— validates distro supportIsElevated()— privilege checkElevationHint(exePath, args)— generates sudo/runas messagessanitizeHost(in string)— hostname sanitizationWhy critical: Platform detection errors could cause leases to run with wrong paths or fail privilege checks.
sanitizeHostis a security-sensitive input sanitization function.Recommended tests:
TestSanitizeHostStripsSpecialCharsTestDetectSetsCorrectOSTestStatePathPlatformSpecificTestIsElevatedCurrentContextTestRequireSupportedLinuxRejectsUnknownDistro🟡 MEDIUM —
internal/app/cli.go(196 lines, 0 tests)Functions untested:
RunCLI(args, Runtime)— main CLI dispatch (routes to run/agent/cleanup/version)runEnroll(args, Runtime)— enrollment flow parsingrunAgent(args, Runtime)— agent mode parsingrunCleanup(args, Runtime)— cleanup flow parsinginterruptContext()— signal handlingprintHelp()— help outputWhy important: CLI dispatch is the user-facing entry point. Flag parsing bugs here surface as confusing errors. The
interruptContextfunction handles graceful shutdown.Recommended tests:
TestRunCLIDispatchesRunCommandTestRunCLIDispatchesAgentCommandTestRunCLIDispatchesCleanupCommandTestRunCLIUnknownCommandReturnsErrorTestRunCLIPrintsHelp🟡 MEDIUM —
internal/platform/exec.go(41 lines, 0 tests)Functions untested:
Runner.Run(ctx, args)— executes commands with context cancellationRunner.RunWithTimeout(timeout, args)— timeout-wrapped executionWhy important: Command execution is security-sensitive. These wrap
os/execcalls that run Tailscale commands on the system. Context cancellation and timeout behavior should be verified.Recommended tests:
TestRunnerRunExecutesCommandTestRunnerRunRespectsContextCancellationTestRunnerRunWithTimeoutExpires🟢 LOW —
internal/logging/logger.go(63 lines, 0 tests)Functions untested:
New(path)— creates log fileInfo/Error— formatted loggingClose()— file cleanupWhy low: Logging is non-critical. Failures here don't affect lease correctness.
Existing Test Quality Notes
config_test.gohas only 1 test — should cover more config loading scenarios (missing fields, invalid JSON, env var precedence)crypto/secret_test.gocovers encrypt/decrypt but not edge cases (empty password, very long passwords, key file permission errors)Recommended Priority Order
Generated by nightshift — test-gap analysis