|
3 | 3 | // This source code is licensed under the MIT license found in the LICENSE file. |
4 | 4 |
|
5 | 5 | // package db provides the data access layer for Keymaster. |
6 | | -// This file contains the PostgreSQL implementation of the database store. |
7 | | -// Note: This implementation is considered experimental. |
| 6 | +// This file contains a minimal PostgreSQL compatibility wrapper. |
| 7 | +// |
| 8 | +// Copyright (c) 2026 Keymaster Team |
| 9 | +// Keymaster - SSH key management system |
| 10 | +// This source code is licensed under the MIT license found in the LICENSE file. |
| 11 | + |
8 | 12 | package db // import "github.com/toeirei/keymaster/internal/db" |
9 | 13 |
|
10 | 14 | import ( |
11 | 15 | "fmt" |
12 | | - "time" |
13 | 16 |
|
14 | 17 | _ "github.com/jackc/pgx/v5/stdlib" // PostgreSQL driver |
15 | | - "github.com/toeirei/keymaster/internal/model" |
16 | | - "github.com/uptrace/bun" |
17 | 18 | ) |
18 | 19 |
|
19 | | -// PostgresStore is the PostgreSQL implementation of the Store interface. |
20 | | -type PostgresStore struct { |
21 | | - bun *bun.DB |
22 | | -} |
23 | | - |
24 | | -// BunDB returns the underlying *bun.DB for the postgres store. |
25 | | -func (s *PostgresStore) BunDB() *bun.DB { |
26 | | - return s.bun |
27 | | -} |
| 20 | +// PostgresStore is a compatibility alias to the consolidated BunStore. |
| 21 | +// This file preserves the pgx driver blank import so runtime builds that |
| 22 | +// expect the driver continue to work while we migrate to a single |
| 23 | +// bun-backed store implementation. |
| 24 | +type PostgresStore = BunStore |
28 | 25 |
|
29 | | -// NewPostgresStore initializes the database connection and creates tables if they don't exist. |
| 26 | +// NewPostgresStore delegates to the canonical db.New initializer and returns |
| 27 | +// a PostgresStore typed pointer for compatibility with existing call sites. |
30 | 28 | func NewPostgresStore(dataSourceName string) (*PostgresStore, error) { |
31 | | - // This function is now a placeholder. The actual initialization happens in InitDB. |
32 | | - // It's kept for potential future logic specific to the store's creation. |
33 | | - s, ok := store.(*PostgresStore) |
34 | | - if !ok { |
35 | | - return nil, fmt.Errorf("internal error: store is not a *PostgresStore") |
36 | | - } |
37 | | - return s, nil |
38 | | -} |
39 | | - |
40 | | -// --- Stubbed Methods --- |
41 | | - |
42 | | -func (s *PostgresStore) GetAllAccounts() ([]model.Account, error) { |
43 | | - return GetAllAccountsBun(s.bun) |
44 | | -} |
45 | | - |
46 | | -func (s *PostgresStore) AddAccount(username, hostname, label, tags string) (int, error) { |
47 | | - id, err := AddAccountBun(s.bun, username, hostname, label, tags) |
48 | | - if err == nil { |
49 | | - _ = s.LogAction("ADD_ACCOUNT", fmt.Sprintf("account: %s@%s", username, hostname)) |
50 | | - } |
51 | | - return id, err |
52 | | -} |
53 | | - |
54 | | -func (s *PostgresStore) DeleteAccount(id int) error { |
55 | | - details := fmt.Sprintf("id: %d", id) |
56 | | - if acc, err2 := GetAccountByIDBun(s.bun, id); err2 == nil && acc != nil { |
57 | | - details = fmt.Sprintf("account: %s@%s", acc.Username, acc.Hostname) |
58 | | - } |
59 | | - err := DeleteAccountBun(s.bun, id) |
60 | | - if err == nil { |
61 | | - _ = s.LogAction("DELETE_ACCOUNT", details) |
62 | | - } |
63 | | - return err |
64 | | -} |
65 | | - |
66 | | -func (s *PostgresStore) UpdateAccountSerial(id, serial int) error { |
67 | | - return UpdateAccountSerialBun(s.bun, id, serial) |
68 | | -} |
69 | | - |
70 | | -func (s *PostgresStore) ToggleAccountStatus(id int) error { |
71 | | - acc, err := GetAccountByIDBun(s.bun, id) |
| 29 | + s, err := New("postgres", dataSourceName) |
72 | 30 | if err != nil { |
73 | | - return err |
74 | | - } |
75 | | - if acc == nil { |
76 | | - return fmt.Errorf("account not found: %d", id) |
77 | | - } |
78 | | - newStatus, err := ToggleAccountStatusBun(s.bun, id) |
79 | | - if err == nil { |
80 | | - details := fmt.Sprintf("account: %s@%s, new_status: %t", acc.Username, acc.Hostname, newStatus) |
81 | | - _ = s.LogAction("TOGGLE_ACCOUNT_STATUS", details) |
82 | | - } |
83 | | - return err |
84 | | -} |
85 | | - |
86 | | -func (s *PostgresStore) UpdateAccountLabel(id int, label string) error { |
87 | | - err := UpdateAccountLabelBun(s.bun, id, label) |
88 | | - if err == nil { |
89 | | - _ = s.LogAction("UPDATE_ACCOUNT_LABEL", fmt.Sprintf("account_id: %d, new_label: '%s'", id, label)) |
90 | | - } |
91 | | - return err |
92 | | -} |
93 | | - |
94 | | -func (s *PostgresStore) UpdateAccountHostname(id int, hostname string) error { |
95 | | - return UpdateAccountHostnameBun(s.bun, id, hostname) |
96 | | -} |
97 | | - |
98 | | -func (s *PostgresStore) UpdateAccountTags(id int, tags string) error { |
99 | | - err := UpdateAccountTagsBun(s.bun, id, tags) |
100 | | - if err == nil { |
101 | | - _ = s.LogAction("UPDATE_ACCOUNT_TAGS", fmt.Sprintf("account_id: %d, new_tags: '%s'", id, tags)) |
102 | | - } |
103 | | - return err |
104 | | -} |
105 | | - |
106 | | -func (s *PostgresStore) UpdateAccountIsDirty(id int, dirty bool) error { |
107 | | - err := UpdateAccountIsDirtyBun(s.bun, id, dirty) |
108 | | - if err == nil { |
109 | | - _ = s.LogAction("UPDATE_ACCOUNT_DIRTY", fmt.Sprintf("account_id: %d, is_dirty: %t", id, dirty)) |
110 | | - } |
111 | | - return err |
112 | | -} |
113 | | - |
114 | | -func (s *PostgresStore) GetAllActiveAccounts() ([]model.Account, error) { |
115 | | - return GetAllActiveAccountsBun(s.bun) |
116 | | -} |
117 | | - |
118 | | -// Public-key CRUD is provided by KeyManager; store keeps Bun helpers. |
119 | | -func (s *PostgresStore) GetKnownHostKey(hostname string) (string, error) { |
120 | | - return GetKnownHostKeyBun(s.bun, hostname) |
121 | | -} |
122 | | - |
123 | | -func (s *PostgresStore) AddKnownHostKey(hostname, key string) error { |
124 | | - err := AddKnownHostKeyBun(s.bun, hostname, key) |
125 | | - if err == nil { |
126 | | - _ = s.LogAction("TRUST_HOST", fmt.Sprintf("hostname: %s", hostname)) |
127 | | - } |
128 | | - return err |
129 | | -} |
130 | | - |
131 | | -func (s *PostgresStore) CreateSystemKey(publicKey, privateKey string) (int, error) { |
132 | | - newSerial, err := CreateSystemKeyBun(s.bun, publicKey, privateKey) |
133 | | - if err == nil { |
134 | | - _ = s.LogAction("CREATE_SYSTEM_KEY", fmt.Sprintf("serial: %d", newSerial)) |
| 31 | + return nil, err |
135 | 32 | } |
136 | | - return newSerial, err |
137 | | -} |
138 | | - |
139 | | -func (s *PostgresStore) RotateSystemKey(publicKey, privateKey string) (int, error) { |
140 | | - newSerial, err := RotateSystemKeyBun(s.bun, publicKey, privateKey) |
141 | | - if err == nil { |
142 | | - _ = s.LogAction("ROTATE_SYSTEM_KEY", fmt.Sprintf("new_serial: %d", newSerial)) |
| 33 | + bs, ok := s.(*BunStore) |
| 34 | + if !ok { |
| 35 | + return nil, fmt.Errorf("internal error: expected *BunStore, got %T", s) |
143 | 36 | } |
144 | | - return newSerial, err |
145 | | -} |
146 | | - |
147 | | -func (s *PostgresStore) GetActiveSystemKey() (*model.SystemKey, error) { |
148 | | - return GetActiveSystemKeyBun(s.bun) |
149 | | -} |
150 | | - |
151 | | -func (s *PostgresStore) GetSystemKeyBySerial(serial int) (*model.SystemKey, error) { |
152 | | - return GetSystemKeyBySerialBun(s.bun, serial) |
153 | | -} |
154 | | - |
155 | | -func (s *PostgresStore) HasSystemKeys() (bool, error) { |
156 | | - return HasSystemKeysBun(s.bun) |
157 | | -} |
158 | | - |
159 | | -// Key<->Account assignment methods are now provided by the `KeyManager`. |
160 | | -// Store implementations keep Bun helpers in `bun_adapter.go` for use by |
161 | | -// the KeyManager adapter. |
162 | | - |
163 | | -// SearchAccounts performs a fuzzy search for accounts using the centralized Bun helper. |
164 | | -func (s *PostgresStore) SearchAccounts(query string) ([]model.Account, error) { |
165 | | - // Delegate via AccountSearcher to decouple callers from Bun specifics. |
166 | | - return NewBunAccountSearcher(s.bun).SearchAccounts(query) |
167 | | -} |
168 | | - |
169 | | -func (s *PostgresStore) GetAllAuditLogEntries() ([]model.AuditLogEntry, error) { |
170 | | - return GetAllAuditLogEntriesBun(s.bun) |
171 | | -} |
172 | | - |
173 | | -func (s *PostgresStore) LogAction(action string, details string) error { |
174 | | - // Delegate to Bun-backed helper which also derives current OS user. |
175 | | - return LogActionBun(s.bun, action, details) |
176 | | -} |
177 | | - |
178 | | -// SaveBootstrapSession saves a bootstrap session to the database. |
179 | | -func (s *PostgresStore) SaveBootstrapSession(id, username, hostname, label, tags, tempPublicKey string, expiresAt time.Time, status string) error { |
180 | | - return SaveBootstrapSessionBun(s.bun, id, username, hostname, label, tags, tempPublicKey, expiresAt, status) |
181 | | -} |
182 | | - |
183 | | -// GetBootstrapSession retrieves a bootstrap session by ID. |
184 | | -func (s *PostgresStore) GetBootstrapSession(id string) (*model.BootstrapSession, error) { |
185 | | - return GetBootstrapSessionBun(s.bun, id) |
186 | | -} |
187 | | - |
188 | | -// DeleteBootstrapSession removes a bootstrap session from the database. |
189 | | -func (s *PostgresStore) DeleteBootstrapSession(id string) error { |
190 | | - return DeleteBootstrapSessionBun(s.bun, id) |
191 | | -} |
192 | | - |
193 | | -// UpdateBootstrapSessionStatus updates the status of a bootstrap session. |
194 | | -func (s *PostgresStore) UpdateBootstrapSessionStatus(id string, status string) error { |
195 | | - return UpdateBootstrapSessionStatusBun(s.bun, id, status) |
196 | | -} |
197 | | - |
198 | | -// GetExpiredBootstrapSessions returns all expired bootstrap sessions. |
199 | | -func (s *PostgresStore) GetExpiredBootstrapSessions() ([]*model.BootstrapSession, error) { |
200 | | - return GetExpiredBootstrapSessionsBun(s.bun) |
201 | | -} |
202 | | - |
203 | | -// GetOrphanedBootstrapSessions returns all orphaned bootstrap sessions. |
204 | | -func (s *PostgresStore) GetOrphanedBootstrapSessions() ([]*model.BootstrapSession, error) { |
205 | | - return GetOrphanedBootstrapSessionsBun(s.bun) |
206 | | -} |
207 | | - |
208 | | -// ExportDataForBackup retrieves all data from the database for a backup. |
209 | | -// It uses a transaction to ensure a consistent snapshot of the data. |
210 | | -func (s *PostgresStore) ExportDataForBackup() (*model.BackupData, error) { |
211 | | - return ExportDataForBackupBun(s.bun) |
212 | | -} |
213 | | - |
214 | | -// ImportDataFromBackup restores the database from a backup data structure. |
215 | | -// It performs a full wipe-and-replace within a single transaction to ensure atomicity. |
216 | | -func (s *PostgresStore) ImportDataFromBackup(backup *model.BackupData) error { |
217 | | - return ImportDataFromBackupBun(s.bun, backup) |
218 | | -} |
219 | | - |
220 | | -// IntegrateDataFromBackup restores data from a backup in a non-destructive way, |
221 | | -// skipping entries that already exist. |
222 | | -func (s *PostgresStore) IntegrateDataFromBackup(backup *model.BackupData) error { |
223 | | - return IntegrateDataFromBackupBun(s.bun, backup) |
| 37 | + return (*PostgresStore)(bs), nil |
224 | 38 | } |
0 commit comments