security: hardening по результатам аудита безопасности

This commit is contained in:
2026-08-08 22:48:16 +03:00
parent 8c8631ac9c
commit bf2bceb520
18 changed files with 400 additions and 20 deletions
+102 -1
View File
@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io"
"os"
"os/exec"
"reflect"
"strings"
@@ -282,11 +283,15 @@ func TestDump_EnvVars(t *testing.T) {
}
envStr := strings.Join(capturedCmd.Env, "\n")
if strings.Contains(envStr, "PGPASSWORD=") {
t.Errorf("PGPASSWORD must not be passed to pg_dump subprocess")
}
wantEnvVars := []string{
"PGHOST=myhost",
"PGPORT=5433",
"PGUSER=myuser",
"PGPASSWORD=mypass",
"PGDATABASE=mydb",
}
for _, wantEnv := range wantEnvVars {
@@ -294,6 +299,102 @@ func TestDump_EnvVars(t *testing.T) {
t.Errorf("env missing %q", wantEnv)
}
}
if !strings.Contains(envStr, "PGPASSFILE=") {
t.Errorf("PGPASSFILE must be set when a password is provided")
}
}
func TestDump_PgpassFileRemovedAfterRun(t *testing.T) {
var capturedCmd *exec.Cmd
adapter := &adapter{
commandContext: func(ctx context.Context, name string, arg ...string) *exec.Cmd {
capturedCmd = exec.CommandContext(ctx, "sh", "-c", "exit 0")
return capturedCmd
},
}
err := adapter.Dump(
context.Background(),
pgdump.Options{
Password: "secret",
Database: "mydb",
},
io.Discard,
)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
envStr := strings.Join(capturedCmd.Env, "\n")
passFilePrefix := "PGPASSFILE="
idx := strings.Index(envStr, passFilePrefix)
if idx == -1 {
t.Fatalf("PGPASSFILE not found in env")
}
pgpassPath := envStr[idx+len(passFilePrefix):]
if newlineIdx := strings.Index(pgpassPath, "\n"); newlineIdx != -1 {
pgpassPath = pgpassPath[:newlineIdx]
}
if _, statErr := os.Stat(pgpassPath); !os.IsNotExist(statErr) {
t.Errorf("temporary pgpass file %s was not removed after Dump returned", pgpassPath)
}
}
func TestWritePgPassFile_Permissions(t *testing.T) {
path, cleanup, err := writePgPassFile(pgdump.Options{
Host: "myhost",
Port: 5432,
Database: "mydb",
User: "myuser",
Password: "secret",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
defer cleanup()
info, err := os.Stat(path)
if err != nil {
t.Fatalf("stat pgpass file: %v", err)
}
if info.Mode().Perm() != 0o600 {
t.Errorf("pgpass file permissions = %o, want %o", info.Mode().Perm(), 0o600)
}
content, err := os.ReadFile(path)
if err != nil {
t.Fatalf("read pgpass file: %v", err)
}
want := "myhost:5432:mydb:myuser:secret\n"
if string(content) != want {
t.Errorf("pgpass content = %q, want %q", string(content), want)
}
}
func TestDump_InvalidExcludeTable(t *testing.T) {
adapter := &adapter{
commandContext: func(ctx context.Context, name string, arg ...string) *exec.Cmd {
return exec.CommandContext(ctx, "sh", "-c", "exit 0")
},
}
err := adapter.Dump(
context.Background(),
pgdump.Options{
Database: "testdb",
ExcludeTables: []string{"table; DROP TABLE users;--"},
},
io.Discard,
)
if err == nil {
t.Fatal("expected error for invalid exclude-table identifier")
}
if !strings.Contains(err.Error(), "invalid exclude-table identifier") {
t.Errorf("error = %v, want invalid exclude-table identifier", err)
}
}
func TestDump_PipeWriterClosed(t *testing.T) {