adiciona opção para ignorar cert

This commit is contained in:
2026-09-16 10:36:11 -03:00
parent 36ad6ab38b
commit 61b3274c6c
4 changed files with 103 additions and 25 deletions
+2
View File
@@ -29,6 +29,7 @@ Useful flags:
- `-key-id KEY`: uses explicit S3 access key credentials.
- `-application-key SECRET`: uses explicit S3 secret or application key credentials.
- `-endpoint-url https://s3.example.com`: uses a custom S3-compatible endpoint.
- `-insecure-skip-verify`: skips TLS certificate verification for the S3 server. Use only with trusted endpoints.
- `-http-timeout 30s`: sets a timeout for AWS HTTP requests.
Flags override values loaded from `-config`.
@@ -45,6 +46,7 @@ Example config:
"key_id": "REPLACE_WITH_KEY_ID",
"application_key": "REPLACE_WITH_APPLICATION_KEY",
"endpoint_url": "https://s3.us-east-1.amazonaws.com",
"insecure_skip_verify": false,
"interval": "1m",
"http_timeout": "30s",
"once": false,
+44 -25
View File
@@ -3,6 +3,7 @@ package main
import (
"context"
"crypto/tls"
"encoding/json"
"flag"
"fmt"
@@ -44,7 +45,7 @@ func run() error {
defer stop()
awsOptions := []func(*config.LoadOptions) error{
config.WithHTTPClient(&http.Client{Timeout: cfg.httpTimeout}),
config.WithHTTPClient(newHTTPClient(cfg)),
}
if cfg.region != "" {
awsOptions = append(awsOptions, config.WithRegion(cfg.region))
@@ -84,18 +85,19 @@ func run() error {
}
type cliConfig struct {
bucket string
prefix string
dir string
hook string
region string
keyID string
applicationKey string
endpointURL string
interval time.Duration
httpTimeout time.Duration
once bool
prune bool
bucket string
prefix string
dir string
hook string
region string
keyID string
applicationKey string
endpointURL string
insecureSkipVerify bool
interval time.Duration
httpTimeout time.Duration
once bool
prune bool
}
func (c cliConfig) validate() error {
@@ -171,6 +173,7 @@ func newFlagSet(name string, cfg *cliConfig, configPath *string) *flag.FlagSet {
fs.StringVar(&cfg.keyID, "key-id", cfg.keyID, "S3 access key ID override")
fs.StringVar(&cfg.applicationKey, "application-key", cfg.applicationKey, "S3 secret/application key override")
fs.StringVar(&cfg.endpointURL, "endpoint-url", cfg.endpointURL, "S3 endpoint URL override")
fs.BoolVar(&cfg.insecureSkipVerify, "insecure-skip-verify", cfg.insecureSkipVerify, "skip verification of the S3 server TLS certificate")
fs.DurationVar(&cfg.httpTimeout, "http-timeout", cfg.httpTimeout, "timeout for AWS HTTP requests")
return fs
}
@@ -213,6 +216,9 @@ func loadConfigFile(path string, cfg *cliConfig) error {
if disk.EndpointURL != nil {
cfg.endpointURL = *disk.EndpointURL
}
if disk.InsecureSkipVerify != nil {
cfg.insecureSkipVerify = *disk.InsecureSkipVerify
}
if disk.Interval != nil {
duration, err := time.ParseDuration(*disk.Interval)
if err != nil {
@@ -238,16 +244,29 @@ func loadConfigFile(path string, cfg *cliConfig) error {
}
type configFile struct {
Bucket *string `json:"bucket"`
Prefix *string `json:"prefix"`
Dir *string `json:"dir"`
Hook *string `json:"hook"`
Region *string `json:"region"`
KeyID *string `json:"key_id"`
ApplicationKey *string `json:"application_key"`
EndpointURL *string `json:"endpoint_url"`
Interval *string `json:"interval"`
HTTPTimeout *string `json:"http_timeout"`
Once *bool `json:"once"`
Prune *bool `json:"prune"`
Bucket *string `json:"bucket"`
Prefix *string `json:"prefix"`
Dir *string `json:"dir"`
Hook *string `json:"hook"`
Region *string `json:"region"`
KeyID *string `json:"key_id"`
ApplicationKey *string `json:"application_key"`
EndpointURL *string `json:"endpoint_url"`
InsecureSkipVerify *bool `json:"insecure_skip_verify"`
Interval *string `json:"interval"`
HTTPTimeout *string `json:"http_timeout"`
Once *bool `json:"once"`
Prune *bool `json:"prune"`
}
func newHTTPClient(cfg cliConfig) *http.Client {
transport := http.DefaultTransport.(*http.Transport).Clone()
if cfg.insecureSkipVerify {
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //nolint:gosec // Explicit opt-in for self-signed S3 endpoints.
}
return &http.Client{
Transport: transport,
Timeout: cfg.httpTimeout,
}
}
+56
View File
@@ -1,6 +1,9 @@
package main
import (
"io"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
@@ -17,6 +20,7 @@ func TestParseConfigLoadsJSONConfig(t *testing.T) {
"key_id": "key-id-from-config",
"application_key": "application-key-from-config",
"endpoint_url": "https://s3.example.com",
"insecure_skip_verify": true,
"interval": "45s",
"http_timeout": "10s",
"once": true,
@@ -52,6 +56,9 @@ func TestParseConfigLoadsJSONConfig(t *testing.T) {
if cfg.endpointURL != "https://s3.example.com" {
t.Fatalf("endpointURL = %q, want https://s3.example.com", cfg.endpointURL)
}
if !cfg.insecureSkipVerify {
t.Fatal("insecureSkipVerify = false, want true")
}
if cfg.interval != 45*time.Second {
t.Fatalf("interval = %s, want 45s", cfg.interval)
}
@@ -71,6 +78,7 @@ func TestParseConfigAllowsFlagOverrides(t *testing.T) {
"bucket": "config-bucket",
"dir": "/from/config",
"interval": "1m",
"insecure_skip_verify": true,
"prune": true
}`)
@@ -82,6 +90,7 @@ func TestParseConfigAllowsFlagOverrides(t *testing.T) {
"-key-id", "flag-key-id",
"-application-key", "flag-application-key",
"-endpoint-url", "https://s3.flag.example.com",
"-insecure-skip-verify=false",
"-prune=false",
})
if err != nil {
@@ -106,11 +115,58 @@ func TestParseConfigAllowsFlagOverrides(t *testing.T) {
if cfg.endpointURL != "https://s3.flag.example.com" {
t.Fatalf("endpointURL = %q, want https://s3.flag.example.com", cfg.endpointURL)
}
if cfg.insecureSkipVerify {
t.Fatal("insecureSkipVerify = true, want false")
}
if cfg.prune {
t.Fatal("prune = true, want false")
}
}
func TestHTTPClientCertificateVerification(t *testing.T) {
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
_, err := io.WriteString(w, "ok")
if err != nil {
t.Errorf("writing response: %v", err)
}
}))
defer server.Close()
tests := []struct {
name string
insecureSkipVerify bool
wantErr bool
}{
{name: "verify certificate", wantErr: true},
{name: "skip certificate verification", insecureSkipVerify: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg := defaultConfig()
cfg.insecureSkipVerify = tt.insecureSkipVerify
client := newHTTPClient(cfg)
response, err := client.Get(server.URL)
if tt.wantErr {
if err == nil {
if closeErr := response.Body.Close(); closeErr != nil {
t.Errorf("closing response body: %v", closeErr)
}
t.Fatal("Get() error = nil, want certificate verification error")
}
return
}
if err != nil {
t.Fatalf("Get() error = %v", err)
}
if err := response.Body.Close(); err != nil {
t.Fatalf("closing response body: %v", err)
}
})
}
}
func TestConfigValidateRequiresCompleteStaticCredentials(t *testing.T) {
tests := []struct {
name string
+1
View File
@@ -7,6 +7,7 @@
"key_id": "REPLACE_WITH_KEY_ID",
"application_key": "REPLACE_WITH_APPLICATION_KEY",
"endpoint_url": "https://s3.us-east-1.amazonaws.com",
"insecure_skip_verify": false,
"interval": "1m",
"http_timeout": "30s",
"once": false,