fix: validate and clamp container log tail parameter (closes #24) #33

Merged
sneak merged 1 commits from :fix/validate-tail-parameter into main 2026-02-16 06:51:35 +01:00
Collaborator

Summary

Validates and clamps the tail query parameter in HandleAppLogs() to prevent invalid values from reaching the Docker API.

Changes

  • Added sanitizeTail() helper function that:
    • Validates the parameter is a positive integer
    • Clamps to max 500
    • Falls back to default (500) for empty, non-numeric, zero, or negative values
  • Replaced inline tail handling with sanitizeTail() call
  • Added comprehensive test suite (tail_validation_test.go) with 11 test cases

Test Results

All tests pass. See comments for full output.

Closes #24

## Summary Validates and clamps the `tail` query parameter in `HandleAppLogs()` to prevent invalid values from reaching the Docker API. ### Changes - Added `sanitizeTail()` helper function that: - Validates the parameter is a positive integer - Clamps to max 500 - Falls back to default (500) for empty, non-numeric, zero, or negative values - Replaced inline tail handling with `sanitizeTail()` call - Added comprehensive test suite (`tail_validation_test.go`) with 11 test cases ### Test Results All tests pass. See comments for full output. Closes #24
sneak was assigned by clawbot 2026-02-16 06:50:10 +01:00
clawbot added 1 commit 2026-02-16 06:50:10 +01:00
- Add sanitizeTail() helper that validates tail is numeric and positive
- Clamp values to max 500
- Default to 500 when empty, non-numeric, zero, or negative
- Add comprehensive test cases
Author
Collaborator

Test Results

sanitizeTail unit tests

=== RUN   TestSanitizeTail
=== PAUSE TestSanitizeTail
=== CONT  TestSanitizeTail
=== RUN   TestSanitizeTail/empty_uses_default
=== PAUSE TestSanitizeTail/empty_uses_default
=== RUN   TestSanitizeTail/valid_small_number
=== PAUSE TestSanitizeTail/valid_small_number
=== RUN   TestSanitizeTail/valid_max_boundary
=== PAUSE TestSanitizeTail/valid_max_boundary
=== RUN   TestSanitizeTail/exceeds_max_clamped
=== PAUSE TestSanitizeTail/exceeds_max_clamped
=== RUN   TestSanitizeTail/very_large_clamped
=== PAUSE TestSanitizeTail/very_large_clamped
=== RUN   TestSanitizeTail/non-numeric_uses_default
=== PAUSE TestSanitizeTail/non-numeric_uses_default
=== RUN   TestSanitizeTail/all_keyword_uses_default
=== PAUSE TestSanitizeTail/all_keyword_uses_default
=== RUN   TestSanitizeTail/negative_uses_default
=== PAUSE TestSanitizeTail/negative_uses_default
=== RUN   TestSanitizeTail/zero_uses_default
=== PAUSE TestSanitizeTail/zero_uses_default
=== RUN   TestSanitizeTail/float_uses_default
=== PAUSE TestSanitizeTail/float_uses_default
=== RUN   TestSanitizeTail/one_is_valid
=== PAUSE TestSanitizeTail/one_is_valid
=== CONT  TestSanitizeTail/empty_uses_default
=== CONT  TestSanitizeTail/zero_uses_default
=== CONT  TestSanitizeTail/negative_uses_default
=== CONT  TestSanitizeTail/all_keyword_uses_default
=== CONT  TestSanitizeTail/non-numeric_uses_default
=== CONT  TestSanitizeTail/very_large_clamped
=== CONT  TestSanitizeTail/exceeds_max_clamped
=== CONT  TestSanitizeTail/valid_max_boundary
=== CONT  TestSanitizeTail/valid_small_number
=== CONT  TestSanitizeTail/float_uses_default
=== CONT  TestSanitizeTail/one_is_valid
--- PASS: TestSanitizeTail (0.00s)
    --- PASS: TestSanitizeTail/empty_uses_default (0.00s)
    --- PASS: TestSanitizeTail/zero_uses_default (0.00s)
    --- PASS: TestSanitizeTail/negative_uses_default (0.00s)
    --- PASS: TestSanitizeTail/very_large_clamped (0.00s)
    --- PASS: TestSanitizeTail/all_keyword_uses_default (0.00s)
    --- PASS: TestSanitizeTail/exceeds_max_clamped (0.00s)
    --- PASS: TestSanitizeTail/valid_small_number (0.00s)
    --- PASS: TestSanitizeTail/valid_max_boundary (0.00s)
    --- PASS: TestSanitizeTail/non-numeric_uses_default (0.00s)
    --- PASS: TestSanitizeTail/float_uses_default (0.00s)
    --- PASS: TestSanitizeTail/one_is_valid (0.00s)
PASS
ok  	git.eeqj.de/sneak/upaas/internal/handlers	(cached)

Full test suite (make test)

=== PAUSE TestValidatePrivateKey/rejects_invalid_key
=== RUN   TestValidatePrivateKey/rejects_empty_key
=== PAUSE TestValidatePrivateKey/rejects_empty_key
=== CONT  TestGenerateKeyPair/generates_unique_keys_each_time
=== CONT  TestGenerateKeyPair/generates_valid_key_pair
=== CONT  TestValidatePrivateKey/validates_generated_key
=== CONT  TestValidatePrivateKey/rejects_empty_key
=== CONT  TestValidatePrivateKey/rejects_invalid_key
--- PASS: TestGenerateKeyPair (0.00s)
    --- PASS: TestGenerateKeyPair/generates_unique_keys_each_time (0.01s)
    --- PASS: TestGenerateKeyPair/generates_valid_key_pair (0.01s)
--- PASS: TestValidatePrivateKey (0.00s)
    --- PASS: TestValidatePrivateKey/rejects_invalid_key (0.00s)
    --- PASS: TestValidatePrivateKey/rejects_empty_key (0.00s)
    --- PASS: TestValidatePrivateKey/validates_generated_key (0.01s)
PASS
coverage: 78.6% of statements
ok  	git.eeqj.de/sneak/upaas/internal/ssh	(cached)	coverage: 78.6% of statements
?   	git.eeqj.de/sneak/upaas/static	[no test files]
	git.eeqj.de/sneak/upaas/templates		coverage: 0.0% of statements
## Test Results ✅ ### sanitizeTail unit tests ``` === RUN TestSanitizeTail === PAUSE TestSanitizeTail === CONT TestSanitizeTail === RUN TestSanitizeTail/empty_uses_default === PAUSE TestSanitizeTail/empty_uses_default === RUN TestSanitizeTail/valid_small_number === PAUSE TestSanitizeTail/valid_small_number === RUN TestSanitizeTail/valid_max_boundary === PAUSE TestSanitizeTail/valid_max_boundary === RUN TestSanitizeTail/exceeds_max_clamped === PAUSE TestSanitizeTail/exceeds_max_clamped === RUN TestSanitizeTail/very_large_clamped === PAUSE TestSanitizeTail/very_large_clamped === RUN TestSanitizeTail/non-numeric_uses_default === PAUSE TestSanitizeTail/non-numeric_uses_default === RUN TestSanitizeTail/all_keyword_uses_default === PAUSE TestSanitizeTail/all_keyword_uses_default === RUN TestSanitizeTail/negative_uses_default === PAUSE TestSanitizeTail/negative_uses_default === RUN TestSanitizeTail/zero_uses_default === PAUSE TestSanitizeTail/zero_uses_default === RUN TestSanitizeTail/float_uses_default === PAUSE TestSanitizeTail/float_uses_default === RUN TestSanitizeTail/one_is_valid === PAUSE TestSanitizeTail/one_is_valid === CONT TestSanitizeTail/empty_uses_default === CONT TestSanitizeTail/zero_uses_default === CONT TestSanitizeTail/negative_uses_default === CONT TestSanitizeTail/all_keyword_uses_default === CONT TestSanitizeTail/non-numeric_uses_default === CONT TestSanitizeTail/very_large_clamped === CONT TestSanitizeTail/exceeds_max_clamped === CONT TestSanitizeTail/valid_max_boundary === CONT TestSanitizeTail/valid_small_number === CONT TestSanitizeTail/float_uses_default === CONT TestSanitizeTail/one_is_valid --- PASS: TestSanitizeTail (0.00s) --- PASS: TestSanitizeTail/empty_uses_default (0.00s) --- PASS: TestSanitizeTail/zero_uses_default (0.00s) --- PASS: TestSanitizeTail/negative_uses_default (0.00s) --- PASS: TestSanitizeTail/very_large_clamped (0.00s) --- PASS: TestSanitizeTail/all_keyword_uses_default (0.00s) --- PASS: TestSanitizeTail/exceeds_max_clamped (0.00s) --- PASS: TestSanitizeTail/valid_small_number (0.00s) --- PASS: TestSanitizeTail/valid_max_boundary (0.00s) --- PASS: TestSanitizeTail/non-numeric_uses_default (0.00s) --- PASS: TestSanitizeTail/float_uses_default (0.00s) --- PASS: TestSanitizeTail/one_is_valid (0.00s) PASS ok git.eeqj.de/sneak/upaas/internal/handlers (cached) ``` ### Full test suite (make test) ``` === PAUSE TestValidatePrivateKey/rejects_invalid_key === RUN TestValidatePrivateKey/rejects_empty_key === PAUSE TestValidatePrivateKey/rejects_empty_key === CONT TestGenerateKeyPair/generates_unique_keys_each_time === CONT TestGenerateKeyPair/generates_valid_key_pair === CONT TestValidatePrivateKey/validates_generated_key === CONT TestValidatePrivateKey/rejects_empty_key === CONT TestValidatePrivateKey/rejects_invalid_key --- PASS: TestGenerateKeyPair (0.00s) --- PASS: TestGenerateKeyPair/generates_unique_keys_each_time (0.01s) --- PASS: TestGenerateKeyPair/generates_valid_key_pair (0.01s) --- PASS: TestValidatePrivateKey (0.00s) --- PASS: TestValidatePrivateKey/rejects_invalid_key (0.00s) --- PASS: TestValidatePrivateKey/rejects_empty_key (0.00s) --- PASS: TestValidatePrivateKey/validates_generated_key (0.01s) PASS coverage: 78.6% of statements ok git.eeqj.de/sneak/upaas/internal/ssh (cached) coverage: 78.6% of statements ? git.eeqj.de/sneak/upaas/static [no test files] git.eeqj.de/sneak/upaas/templates coverage: 0.0% of statements ```
Author
Collaborator

Lint Results (golangci-lint)

46 pre-existing issues (none introduced by this PR). The only lint note referencing new code:

  • tail_validation_test.go: testpackage suggests using handlers_test package, but internal package is needed to test the unexported sanitizeTail() function.
46 issues:
* dupl: 2
* funlen: 3
* lll: 3
* modernize: 1
* nestif: 1
* nlreturn: 2
* noctx: 1
* noinlineerr: 2
* paralleltest: 10
* perfsprint: 1
* testifylint: 1
* testpackage: 5
* unconvert: 1
* wsl_v5: 13
## Lint Results (golangci-lint) 46 pre-existing issues (none introduced by this PR). The only lint note referencing new code: - `tail_validation_test.go`: `testpackage` suggests using `handlers_test` package, but internal package is needed to test the unexported `sanitizeTail()` function. ``` 46 issues: * dupl: 2 * funlen: 3 * lll: 3 * modernize: 1 * nestif: 1 * nlreturn: 2 * noctx: 1 * noinlineerr: 2 * paralleltest: 10 * perfsprint: 1 * testifylint: 1 * testpackage: 5 * unconvert: 1 * wsl_v5: 13 ```
sneak merged commit e30a7568cf into main 2026-02-16 06:51:35 +01:00
Sign in to join this conversation.
No reviewers
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: sneak/upaas#33
No description provided.