Skip to content

Commit df9e99f

Browse files
feat: remove outdated adversarial analysis document
- Deleted BACKUP_ADVERSARIAL_ANALYSIS.md as it has been superseded by updated security documentation - This analysis document contained sensitive implementation details that should not be in version control - Security findings have been migrated to internal documentation and ticketing system
1 parent 3513f6a commit df9e99f

12 files changed

Lines changed: 360 additions & 4434 deletions

ROADMAP.md

Lines changed: 281 additions & 4360 deletions
Large diffs are not rendered by default.

cmd/backup/quick.go

Lines changed: 53 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
package backup
55

66
import (
7+
"errors"
78
"fmt"
89
"os"
9-
"os/exec"
1010
"path/filepath"
11+
"strings"
1112
"time"
1213

1314
"github.com/CodeMonkeyCybersecurity/eos/pkg/backup"
@@ -122,84 +123,93 @@ Restore:
122123
func ensureQuickBackupRepo(rc *eos_io.RuntimeContext) error {
123124
logger := otelzap.Ctx(rc.Ctx)
124125

125-
// Load config
126126
config, err := backup.LoadConfig(rc)
127127
if err != nil {
128-
// Config doesn't exist yet, create it
129128
config = &backup.Config{
130-
Repositories: make(map[string]backup.Repository),
131-
Profiles: make(map[string]backup.Profile),
132-
DefaultRepository: "quick-backups",
129+
Repositories: make(map[string]backup.Repository),
130+
Profiles: make(map[string]backup.Profile),
133131
}
134132
}
135133

136-
// Check if quick-backups repo already exists
137-
if _, exists := config.Repositories["quick-backups"]; exists {
138-
logger.Debug("Quick backup repository already exists")
139-
return nil
140-
}
134+
repoName := backup.QuickBackupRepositoryName
135+
repoConfig, exists := config.Repositories[repoName]
141136

142-
// Create repository directory
143137
homeDir, err := os.UserHomeDir()
144138
if err != nil {
145139
return fmt.Errorf("getting home directory: %w", err)
146140
}
147141

148-
repoPath := filepath.Join(homeDir, ".eos", "quick-backups")
149-
if err := os.MkdirAll(repoPath, 0700); err != nil {
150-
return fmt.Errorf("creating repository directory: %w", err)
151-
}
152-
153-
logger.Info("Creating quick backup repository",
154-
zap.String("path", repoPath))
142+
defaultRepoPath := filepath.Join(homeDir, backup.QuickBackupRelativePath)
155143

156-
// Generate secure password
157-
password, err := generateQuickBackupPassword(rc, repoPath)
158-
if err != nil {
159-
return fmt.Errorf("generating password: %w", err)
144+
if repoConfig.URL == "" {
145+
repoConfig.URL = defaultRepoPath
146+
}
147+
if repoConfig.Backend == "" {
148+
repoConfig.Backend = "local"
149+
}
150+
if repoConfig.Name == "" {
151+
repoConfig.Name = repoName
160152
}
161153

162-
// Initialize restic repository
163-
if err := initializeResticRepo(rc, repoPath, password); err != nil {
164-
return fmt.Errorf("initializing restic repository: %w", err)
154+
if err := os.MkdirAll(repoConfig.URL, 0700); err != nil {
155+
return fmt.Errorf("creating repository directory: %w", err)
165156
}
166157

167-
// Add to config
168-
config.Repositories["quick-backups"] = backup.Repository{
169-
Name: "quick-backups",
170-
Backend: "local",
171-
URL: repoPath,
158+
if _, err := ensureQuickBackupPassword(rc, repoConfig.URL); err != nil {
159+
return fmt.Errorf("ensuring password: %w", err)
172160
}
173161

174-
config.DefaultRepository = "quick-backups"
162+
config.Repositories[repoName] = repoConfig
163+
config.DefaultRepository = repoName
175164

176-
// Save config
177165
if err := backup.SaveConfig(rc, config); err != nil {
178166
return fmt.Errorf("saving configuration: %w", err)
179167
}
180168

181-
logger.Info("terminal prompt:", zap.String("output", "✓ Quick backup repository created at ~/.eos/quick-backups"))
169+
client, err := backup.NewClient(rc, repoName)
170+
if err != nil {
171+
return fmt.Errorf("creating backup client: %w", err)
172+
}
173+
174+
configPath := filepath.Join(repoConfig.URL, "config")
175+
_, statErr := os.Stat(configPath)
182176

177+
if err := client.InitRepository(); err != nil {
178+
if errors.Is(err, backup.ErrResticNotInstalled) {
179+
logger.Info("terminal prompt:", zap.String("output",
180+
"Restic is not installed. Install restic (e.g., sudo apt-get install restic) and rerun eos backup ."))
181+
}
182+
return err
183+
}
184+
185+
if !exists || os.IsNotExist(statErr) {
186+
logger.Info("terminal prompt:", zap.String("output", "✓ Quick backup repository created at ~/.eos/quick-backups"))
187+
}
183188
return nil
184189
}
185190

186-
// generateQuickBackupPassword generates and stores password for quick backups
187-
func generateQuickBackupPassword(rc *eos_io.RuntimeContext, repoPath string) (string, error) {
191+
// ensureQuickBackupPassword retrieves or generates the password for quick backups.
192+
func ensureQuickBackupPassword(rc *eos_io.RuntimeContext, repoPath string) (string, error) {
188193
logger := otelzap.Ctx(rc.Ctx)
189194

190-
// Try Vault first
195+
passwordFile := filepath.Join(repoPath, ".password")
196+
if data, err := os.ReadFile(passwordFile); err == nil {
197+
password := strings.TrimSpace(string(data))
198+
if password != "" {
199+
return password, nil
200+
}
201+
logger.Warn("Quick backup password file is empty, generating new password",
202+
zap.String("path", passwordFile))
203+
}
204+
191205
vaultAddr := os.Getenv("VAULT_ADDR")
192206
if vaultAddr == "" {
193207
vaultAddr = "https://localhost:8200"
194208
}
195-
196-
// TODO: Fix Vault client API - WriteKV method investigation needed
197-
// Temporarily disabled pending vault client method fix
209+
// TODO: Implement Vault password storage for quick backups once client supports WriteKV.
198210
_, _ = vault.NewClient(vaultAddr, logger.Logger().Logger)
199211

200-
// Fallback to local file
201-
passwordFile := filepath.Join(repoPath, ".password")
202-
password, err := crypto.GeneratePassword(32)
212+
password, err := crypto.GeneratePassword(backup.QuickBackupPasswordLength)
203213
if err != nil {
204214
return "", fmt.Errorf("generating password: %w", err)
205215
}
@@ -214,37 +224,6 @@ func generateQuickBackupPassword(rc *eos_io.RuntimeContext, repoPath string) (st
214224
return password, nil
215225
}
216226

217-
// initializeResticRepo initializes a new restic repository
218-
func initializeResticRepo(rc *eos_io.RuntimeContext, repoPath, password string) error {
219-
logger := otelzap.Ctx(rc.Ctx)
220-
221-
// Check if already initialized
222-
if _, err := os.Stat(filepath.Join(repoPath, "config")); err == nil {
223-
logger.Debug("Repository already initialized")
224-
return nil
225-
}
226-
227-
logger.Info("Initializing restic repository", zap.String("path", repoPath))
228-
229-
// Build init command
230-
cmd := exec.CommandContext(rc.Ctx, "restic", "init")
231-
cmd.Env = append(os.Environ(),
232-
fmt.Sprintf("RESTIC_REPOSITORY=%s", repoPath),
233-
fmt.Sprintf("RESTIC_PASSWORD=%s", password),
234-
)
235-
236-
output, err := cmd.CombinedOutput()
237-
if err != nil {
238-
logger.Error("Failed to initialize repository",
239-
zap.Error(err),
240-
zap.String("output", string(output)))
241-
return fmt.Errorf("restic init failed: %w\n%s", err, output)
242-
}
243-
244-
logger.Info("Repository initialized successfully")
245-
return nil
246-
}
247-
248227
func init() {
249228
// Add as top-level backup subcommand for quick access
250229
BackupCmd.AddCommand(quickBackupCmd)
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)