security: hardening по результатам аудита безопасности
This commit is contained in:
@@ -23,6 +23,7 @@ import (
|
||||
"git.tswf.io/infra/go-synapse-backupper/pkg/adapters/retention"
|
||||
"git.tswf.io/infra/go-synapse-backupper/pkg/adapters/storage/local"
|
||||
"git.tswf.io/infra/go-synapse-backupper/pkg/domain"
|
||||
"git.tswf.io/infra/go-synapse-backupper/pkg/domain/backup"
|
||||
"git.tswf.io/infra/go-synapse-backupper/pkg/domain/crypto"
|
||||
"git.tswf.io/infra/go-synapse-backupper/pkg/domain/pgdump"
|
||||
)
|
||||
@@ -98,7 +99,7 @@ var backupCmd = &cobra.Command{
|
||||
Database: cfg.PG.Database,
|
||||
User: cfg.PG.User,
|
||||
Password: cfg.PG.Password,
|
||||
Key: fmt.Sprintf("synapse-%s.dump.pqenc", startTime.Format("20060102-150405")),
|
||||
Key: backup.ArtifactKey(startTime),
|
||||
ExcludeTables: cfg.PG.ExcludeTables,
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,6 @@ func setBackupFlags(
|
||||
_ = cmd.Flags().Set("pg-host", "localhost")
|
||||
_ = cmd.Flags().Set("pg-port", "5432")
|
||||
_ = cmd.Flags().Set("pg-user", "testuser")
|
||||
_ = cmd.Flags().Set("pg-password", "testpass")
|
||||
_ = cmd.Flags().Set("pg-database", "testdb")
|
||||
}
|
||||
|
||||
@@ -162,6 +161,7 @@ func TestBackupCmd_Structure(t *testing.T) {
|
||||
|
||||
func TestBackupCmd_Success(t *testing.T) {
|
||||
restoreGlobals(t)
|
||||
t.Setenv("APP_PG_PASSWORD", "testpass")
|
||||
|
||||
backupDir := t.TempDir()
|
||||
pqPath := filepath.Join(backupDir, "pq.pub")
|
||||
@@ -240,7 +240,7 @@ func TestBackupCmd_Success(t *testing.T) {
|
||||
|
||||
key := dumper.receivedOpts.Key
|
||||
matched, _ := regexp.MatchString(
|
||||
`^synapse-\d{8}-\d{6}\.dump\.pqenc$`,
|
||||
`^synapse-\d{8}-\d{6}-[a-f0-9]{6}\.dump\.pqenc$`,
|
||||
key,
|
||||
)
|
||||
if !matched {
|
||||
@@ -300,6 +300,7 @@ func TestBackupCmd_Success(t *testing.T) {
|
||||
|
||||
func TestBackupCmd_PgDumpFailure(t *testing.T) {
|
||||
restoreGlobals(t)
|
||||
t.Setenv("APP_PG_PASSWORD", "testpass")
|
||||
|
||||
backupDir := t.TempDir()
|
||||
pqPath := filepath.Join(backupDir, "pq.pub")
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newHealthcheckCmd() *cobra.Command {
|
||||
var port int
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "healthcheck",
|
||||
Short: "Check the scheduler health endpoint",
|
||||
Hidden: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(cmd.Context(), 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
url := fmt.Sprintf("http://127.0.0.1:%d/healthz", port)
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("build health request: %w", err)
|
||||
}
|
||||
|
||||
response, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("health request failed: %w", err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("health check returned status %d", response.StatusCode)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().IntVar(&port, "port", 8080, "Health check server port")
|
||||
|
||||
return cmd
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHealthcheckCmd_Success(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/healthz" {
|
||||
t.Errorf("unexpected path: %q", r.URL.Path)
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
cmd := newHealthcheckCmd()
|
||||
cmd.SetArgs([]string{"--port", serverPort(server)})
|
||||
if err := cmd.Execute(); err != nil {
|
||||
t.Fatalf("healthcheck failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHealthcheckCmd_Failure(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
cmd := newHealthcheckCmd()
|
||||
cmd.SetArgs([]string{"--port", serverPort(server)})
|
||||
err := cmd.Execute()
|
||||
if err == nil {
|
||||
t.Fatal("expected error for non-OK health status")
|
||||
}
|
||||
}
|
||||
|
||||
func serverPort(server *httptest.Server) string {
|
||||
return server.Listener.Addr().String()[strings.LastIndex(server.Listener.Addr().String(), ":")+1:]
|
||||
}
|
||||
@@ -108,6 +108,12 @@ func newKeygenCmdWithDeps(reg crypto.Registry) *cobra.Command {
|
||||
if err := privFile.Close(); err != nil {
|
||||
return fmt.Errorf("close private key file %s: %w", privPath, err)
|
||||
}
|
||||
if err := os.Chmod(pubPath, 0o644); err != nil {
|
||||
return fmt.Errorf("chmod public key file %s: %w", pubPath, err)
|
||||
}
|
||||
if err := os.Chmod(privPath, 0o600); err != nil {
|
||||
return fmt.Errorf("chmod private key file %s: %w", privPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -23,6 +23,7 @@ func main() {
|
||||
rootCmd.AddCommand(restoreCmd)
|
||||
rootCmd.AddCommand(runCmd)
|
||||
rootCmd.AddCommand(newKeygenCmd())
|
||||
rootCmd.AddCommand(newHealthcheckCmd())
|
||||
rootCmd.AddCommand(generateConfigCmd())
|
||||
|
||||
if err := rootCmd.ExecuteContext(ctx); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user