Files
k3nny f79c64cd44
ci / vet, staticcheck, test, build (push) Failing after 2m32s
release / Build and publish release (push) Successful in 1m17s
feat(security): security hardening, proxy support, and GL045 HTTP include warning
Security fixes:
- Path traversal guard in include: local: — paths with ../ that escape
  the repo root are rejected instead of reading arbitrary host files
- HTTP timeout (30 s) on all fetcher requests to prevent indefinite hangs
- Response size cap (10 MiB) via io.LimitReader to prevent memory exhaustion
- Cache directory and file permissions tightened to 0700/0600
- LSP Content-Length cap (64 MiB) to guard against DoS from a malicious client

New feature:
- --proxy flag on check, graph, and lsp subcommands; also proxy: key in
  .glint.yml; overrides system HTTP_PROXY / HTTPS_PROXY env vars when set;
  cmdGraph and cmdLSP now also load .glint.yml for proxy/token/url fallbacks

New lint rule:
- GL045 (Warning): include: remote: using plain http:// instead of https://

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 21:52:57 +02:00

74 lines
1.6 KiB
Go

package linter
import (
"testing"
"git.k3nny.fr/glint/internal/model"
)
func TestCheckInsecureRemoteInclude(t *testing.T) {
tests := []struct {
name string
include []any
wantGL string // expected rule ID, empty = no findings
}{
{
name: "http URL triggers GL045",
include: []any{map[string]any{"remote": "http://example.com/ci.yml"}},
wantGL: RuleInsecureRemoteInclude,
},
{
name: "https URL is clean",
include: []any{map[string]any{"remote": "https://example.com/ci.yml"}},
},
{
name: "local include ignored",
include: []any{map[string]any{"local": "/templates/ci.yml"}},
},
{
name: "string include ignored",
include: []any{"/templates/ci.yml"},
},
{
name: "no includes",
include: nil,
},
{
name: "mixed: http fires, https does not",
include: []any{
map[string]any{"remote": "https://ok.example.com/ci.yml"},
map[string]any{"remote": "http://bad.example.com/ci.yml"},
},
wantGL: RuleInsecureRemoteInclude,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
p := &model.Pipeline{
Include: tc.include,
Jobs: map[string]model.Job{},
}
findings := checkInsecureRemoteInclude(p)
if tc.wantGL == "" {
if len(findings) != 0 {
t.Errorf("expected no findings, got: %v", findings)
}
return
}
found := false
for _, f := range findings {
if f.Rule == tc.wantGL {
found = true
if f.Severity != Warning {
t.Errorf("severity = %v; want Warning", f.Severity)
}
}
}
if !found {
t.Errorf("expected finding %s, got: %v", tc.wantGL, findings)
}
})
}
}