Skip to content

Commit 589d545

Browse files
committed
feat(backup): restore secret storage by access key
1 parent 79a4180 commit 589d545

File tree

6 files changed

+158
-17
lines changed

6 files changed

+158
-17
lines changed

db/BackupEntity.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,11 @@ func (e Environment) GetID() int {
5656
func (e Environment) GetName() string {
5757
return e.Name
5858
}
59+
60+
func (e SecretStorage) GetID() int {
61+
return e.ID
62+
}
63+
64+
func (e SecretStorage) GetName() string {
65+
return e.Name
66+
}

db/sql/SqlDb.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,26 @@ func (d *SqlDbConnection) Close() {
111111
}
112112
}
113113

114+
func CreateTestStore() *SqlDb {
115+
util.Config = &util.ConfigType{
116+
SQLite: &util.DbConfig{
117+
Hostname: ":memory:",
118+
},
119+
Dialect: "sqlite",
120+
Log: &util.ConfigLog{
121+
Events: &util.EventLogType{},
122+
Tasks: &util.TaskLogType{},
123+
},
124+
}
125+
store := CreateDb(util.DbDriverSQLite)
126+
127+
store.Connect("")
128+
129+
db.Migrate(store, nil)
130+
131+
return store
132+
}
133+
114134
func (d *SqlDbConnection) prepareQueryWithDialect(query string, dialect gorp.Dialect) string {
115135
switch dialect.(type) {
116136
case gorp.PostgresDialect:

services/project/backup.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -252,15 +252,11 @@ func (b *BackupDB) format() (*BackupFormat, error) {
252252
SecretStorage: o,
253253
}
254254

255-
for _, key := range keys {
256-
if *key.StorageID == o.ID {
257-
secretStorages[i].VaultTokenKeyName = key.Name
258-
break
259-
}
260-
}
261-
262255
for k := range keys {
263-
if *keys[k].SourceStorageID == o.ID {
256+
if keys[k].StorageID != nil && *keys[k].StorageID == o.ID {
257+
keys[k].Storage = &o.Name
258+
}
259+
if keys[k].SourceStorageID != nil && *keys[k].SourceStorageID == o.ID {
264260
keys[k].SourceStorage = &o.Name
265261
}
266262
}

services/project/backup_test.go

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package project
22

33
import (
4+
"encoding/json"
5+
"github.com/semaphoreui/semaphore/db/sql"
46
"testing"
57

68
"github.com/semaphoreui/semaphore/db"
7-
"github.com/semaphoreui/semaphore/db/bolt"
89
"github.com/semaphoreui/semaphore/util"
910
"github.com/stretchr/testify/assert"
1011
)
@@ -18,7 +19,7 @@ func TestBackupProject(t *testing.T) {
1819
TmpPath: "/tmp",
1920
}
2021

21-
store := bolt.CreateTestStore()
22+
store := sql.CreateTestStore()
2223

2324
proj, err := store.CreateProject(db.Project{
2425
Name: "Test 123",
@@ -92,6 +93,106 @@ func TestBackupProject(t *testing.T) {
9293
assert.Equal(t, proj.Name, restoredProj.Name)
9394
}
9495

96+
func TestBackup_BackupSecretStorage(t *testing.T) {
97+
util.Config = &util.ConfigType{
98+
TmpPath: "/tmp",
99+
}
100+
101+
store := sql.CreateTestStore()
102+
103+
proj, err := store.CreateProject(db.Project{
104+
Name: "Test 123",
105+
})
106+
assert.NoError(t, err)
107+
108+
storage, err := store.CreateSecretStorage(db.SecretStorage{
109+
ProjectID: proj.ID,
110+
Type: "vault",
111+
Name: "Test",
112+
})
113+
assert.NoError(t, err)
114+
115+
_, err = store.CreateAccessKey(db.AccessKey{
116+
ProjectID: &proj.ID,
117+
Type: db.AccessKeyNone,
118+
StorageID: &storage.ID,
119+
Name: "Test Key",
120+
})
121+
assert.NoError(t, err)
122+
123+
backup, err := GetBackup(proj.ID, store)
124+
assert.NoError(t, err)
125+
assert.Equal(t, proj.ID, backup.Meta.ID)
126+
127+
str, err := backup.Marshal()
128+
assert.NoError(t, err)
129+
130+
var res map[string]any
131+
json.Unmarshal([]byte(str), &res)
132+
133+
assert.Equal(t, `{
134+
"environments": [],
135+
"integration_aliases": [],
136+
"integrations": [],
137+
"inventories": [],
138+
"keys": [
139+
{
140+
"name": "Test Key",
141+
"owner": "",
142+
"storage": "Test",
143+
"type": "none"
144+
}
145+
],
146+
"meta": {
147+
"alert": false,
148+
"max_parallel_tasks": 0,
149+
"name": "Test 123",
150+
"type": ""
151+
},
152+
"repositories": [],
153+
"schedules": [],
154+
"secret_storages": [
155+
{
156+
"name": "Test",
157+
"params": {},
158+
"readonly": false,
159+
"type": "vault"
160+
}
161+
],
162+
"templates": [],
163+
"views": []
164+
}`, str)
165+
166+
restoredBackup := &BackupFormat{}
167+
err = restoredBackup.Unmarshal(str)
168+
assert.NoError(t, err)
169+
assert.Equal(t, proj.Name, restoredBackup.Meta.Name)
170+
171+
user, err := store.CreateUser(db.UserWithPwd{
172+
Pwd: "3412341234123",
173+
User: db.User{
174+
Username: "test",
175+
Name: "Test",
176+
177+
Admin: true,
178+
},
179+
})
180+
assert.NoError(t, err)
181+
182+
restoredProj, err := restoredBackup.Restore(user, store)
183+
assert.Nil(t, err)
184+
185+
restoredStorages, err := store.GetSecretStorages(restoredProj.ID)
186+
assert.NoError(t, err)
187+
assert.Len(t, restoredStorages, 1)
188+
189+
restoredKeys, err := store.GetAccessKeys(restoredProj.ID, db.GetAccessKeyOptions{}, db.RetrieveQueryParams{})
190+
assert.NoError(t, err)
191+
assert.Len(t, restoredKeys, 1)
192+
193+
assert.Equal(t, *restoredKeys[0].StorageID, restoredStorages[0].ID)
194+
}
195+
95196
func isUnique(items []testItem) bool {
96197
for i, item := range items {
97198
for k, other := range items {

services/project/restore.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,22 @@ func (e BackupAccessKey) Restore(store db.Store, b *BackupDB) error {
116116
key := e.AccessKey
117117
key.ProjectID = &b.meta.ID
118118

119+
if e.Storage != nil {
120+
storage := findEntityByName[db.SecretStorage](e.Storage, b.secretStorages)
121+
if storage == nil {
122+
return fmt.Errorf("secret storage does not exist in secret_storage[].name")
123+
}
124+
key.StorageID = &storage.ID
125+
}
126+
127+
if e.SourceStorage != nil {
128+
storage := findEntityByName[db.SecretStorage](e.SourceStorage, b.secretStorages)
129+
if storage == nil {
130+
return fmt.Errorf("secret storage does not exist in secret_storage[].name")
131+
}
132+
key.StorageID = &storage.ID
133+
}
134+
119135
newKey, err := store.CreateAccessKey(key)
120136

121137
if err != nil {
@@ -461,6 +477,12 @@ func (backup *BackupFormat) Restore(user db.User, store db.Store) (*db.Project,
461477

462478
b.meta = newProject
463479

480+
for i, o := range backup.SecretStorages {
481+
if err := o.Restore(store, &b); err != nil {
482+
return nil, fmt.Errorf("error at secret storage[%d]: %s", i, err.Error())
483+
}
484+
}
485+
464486
for i, o := range backup.Environments {
465487
if err := o.Restore(store, &b); err != nil {
466488
return nil, fmt.Errorf("error at environments[%d]: %s", i, err.Error())
@@ -529,11 +551,5 @@ func (backup *BackupFormat) Restore(user db.User, store db.Store) (*db.Project,
529551
}
530552
}
531553

532-
for i, o := range backup.SecretStorages {
533-
if err := o.Restore(store, &b); err != nil {
534-
return nil, fmt.Errorf("error at secret storage[%d]: %s", i, err.Error())
535-
}
536-
}
537-
538554
return &newProject, nil
539555
}

services/project/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ type BackupEnvironment struct {
4848
type BackupAccessKey struct {
4949
db.AccessKey
5050
SourceStorage *string `backup:"source_storage"`
51+
Storage *string `backup:"storage"`
5152
}
5253

5354
type BackupSchedule struct {
@@ -101,7 +102,6 @@ type BackupIntegration struct {
101102

102103
type BackupSecretStorage struct {
103104
db.SecretStorage
104-
VaultTokenKeyName string `backup:"vault_token_key_name"`
105105
}
106106

107107
type BackupEntry interface {

0 commit comments

Comments
 (0)