Skip to content

Commit 44eae68

Browse files
authored
feat(api,cli): new feature to list and check encrypted secrets (#5648)
Signed-off-by: francois samin <francois.samin@corp.ovh.com>
1 parent 28b6826 commit 44eae68

File tree

11 files changed

+139
-9
lines changed

11 files changed

+139
-9
lines changed

cli/cdsctl/encrypt.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ my-data: 01234567890987654321`,
5959
}
6060

6161
func encrypt() *cobra.Command {
62-
return cli.NewCommand(encryptCmd, encryptRun, nil, withAllCommandModifiers()...)
62+
return cli.NewCommand(encryptCmd, encryptRun, cli.SubCommands{encryptList()}, withAllCommandModifiers()...)
6363
}
6464

6565
func encryptRun(v cli.Values) error {
@@ -76,3 +76,23 @@ func encryptRun(v cli.Values) error {
7676
fmt.Printf("%s: %s\n", variable.Name, variable.Value)
7777
return nil
7878
}
79+
80+
var encryptListCmd = cli.Command{
81+
Name: "list",
82+
Short: "List all the encrypted variable of your CDS project",
83+
Ctx: []cli.Arg{
84+
{Name: _ProjectKey},
85+
},
86+
}
87+
88+
func encryptList() *cobra.Command {
89+
return cli.NewListCommand(encryptListCmd, encryptListRun, nil, withAllCommandModifiers()...)
90+
}
91+
92+
func encryptListRun(v cli.Values) (cli.ListResult, error) {
93+
secrets, err := client.VariableListEncrypt(v.GetString(_ProjectKey))
94+
if err != nil {
95+
return nil, err
96+
}
97+
return cli.AsListResult(secrets), nil
98+
}

engine/api/api_routes.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ func (api *API) InitRouter() {
158158
r.Handle("/project/{permProjectKey}/group/{groupName}", Scope(sdk.AuthConsumerScopeProject), r.PUT(api.putGroupRoleOnProjectHandler), r.DELETE(api.deleteGroupFromProjectHandler))
159159
r.Handle("/project/{permProjectKey}/variable", Scope(sdk.AuthConsumerScopeProject), r.GET(api.getVariablesInProjectHandler))
160160
r.Handle("/project/{permProjectKey}/encrypt", Scope(sdk.AuthConsumerScopeProject), r.POST(api.postEncryptVariableHandler))
161+
r.Handle("/project/{permProjectKey}/encrypt/list", Scope(sdk.AuthConsumerScopeProject), r.GET(api.getListEncryptVariableHandler))
161162
r.Handle("/project/{permProjectKey}/variable/audit", Scope(sdk.AuthConsumerScopeProject), r.GET(api.getVariablesAuditInProjectnHandler))
162163
r.Handle("/project/{permProjectKey}/variable/{name}", Scope(sdk.AuthConsumerScopeProject), r.GET(api.getVariableInProjectHandler), r.POST(api.addVariableInProjectHandler), r.PUT(api.updateVariableInProjectHandler), r.DELETE(api.deleteVariableFromProjectHandler))
163164
r.Handle("/project/{permProjectKey}/variable/{name}/audit", Scope(sdk.AuthConsumerScopeProject), r.GET(api.getVariableAuditInProjectHandler))

engine/api/environment/environment_importer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func Import(db gorpmapper.SqlExecutorWithTx, proj sdk.Project, env *sdk.Environm
6868
//ImportInto import variables and groups on an existing environment
6969
func ImportInto(ctx context.Context, db gorpmapper.SqlExecutorWithTx, env *sdk.Environment, into *sdk.Environment, msgChan chan<- sdk.Message, u sdk.Identifiable) error {
7070
var updateVar = func(v *sdk.EnvironmentVariable) {
71-
log.Debug(ctx, "ImportInto> Updating var %s", v.Name)
71+
log.Debug(ctx, "ImportInto> Updating var %q with value %q", v.Name, v.Value)
7272

7373
varBefore, errV := LoadVariable(db, into.ID, v.Name)
7474
if errV != nil {

engine/api/project/key.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package project
33
import (
44
"bytes"
55
"compress/gzip"
6+
"context"
67
"crypto/rand"
78
"database/sql"
89
"encoding/base64"
@@ -18,7 +19,9 @@ import (
1819
)
1920

2021
func init() {
21-
gorpmapping.Register(gorpmapping.New(dbEncryptedData{}, "encrypted_data", false, "token"))
22+
gorpmapping.Register(gorpmapping.New(dbEncryptedData{}, "encrypted_data", false, "project_id", "content_name"))
23+
gorpmapping.Register(gorpmapping.New(sdk.Secret{}, "encrypted_data", false, "project_id", "content_name"))
24+
2225
}
2326

2427
type dbEncryptedData struct {
@@ -28,6 +31,15 @@ type dbEncryptedData struct {
2831
EncyptedContent []byte `db:"encrypted_content"`
2932
}
3033

34+
func ListEncryptedData(ctx context.Context, db gorp.SqlExecutor, projectID int64) ([]sdk.Secret, error) {
35+
var res []sdk.Secret
36+
query := gorpmapping.NewQuery("select content_name, token from encrypted_data where project_id = $1").Args(projectID)
37+
if err := gorpmapping.GetAll(ctx, db, query, &res); err != nil {
38+
return nil, sdk.WithStack(err)
39+
}
40+
return res, nil
41+
}
42+
3143
// EncryptWithBuiltinKey encrypt a content with the builtin gpg key encode, compress it and encode with base64
3244
func EncryptWithBuiltinKey(db gorp.SqlExecutor, projectID int64, name, content string) (string, error) {
3345
existingToken, err := db.SelectStr("select token from encrypted_data where project_id = $1 and content_name = $2", projectID, name)

engine/api/project_variable.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,47 @@ import (
55
"net/http"
66

77
"github.com/gorilla/mux"
8+
"github.com/rockbears/log"
89

910
"github.com/ovh/cds/engine/api/event"
1011
"github.com/ovh/cds/engine/api/project"
1112
"github.com/ovh/cds/engine/service"
1213
"github.com/ovh/cds/sdk"
1314
)
1415

16+
func (api *API) getListEncryptVariableHandler() service.Handler {
17+
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
18+
vars := mux.Vars(r)
19+
key := vars[permProjectKey]
20+
21+
p, err := project.Load(ctx, api.mustDB(), key)
22+
if err != nil {
23+
return err
24+
}
25+
26+
res, err := project.ListEncryptedData(ctx, api.mustDB(), p.ID)
27+
if err != nil {
28+
return err
29+
}
30+
31+
for i := range res {
32+
decryptedData, err := project.DecryptWithBuiltinKey(api.mustDB(), p.ID, res[i].Token)
33+
if err != nil {
34+
log.Error(ctx, "unable to decrypt data %s: %v", res[i].Token, err)
35+
res[i].Status = "decryption failed"
36+
}
37+
38+
if decryptedData == sdk.PasswordPlaceholder {
39+
res[i].Status = "password placeholder detected"
40+
}
41+
42+
res[i].Status = "OK"
43+
}
44+
45+
return service.WriteJSON(w, res, http.StatusOK)
46+
}
47+
}
48+
1549
func (api *API) postEncryptVariableHandler() service.Handler {
1650
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
1751
vars := mux.Vars(r)

engine/cdn/storage/storageunit_run.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ func (x *RunningStorageUnits) FillSyncItemChannel(ctx context.Context, s Storage
2323
if err := x.cache.ScoredSetRevRange(ctx, cache.Key(KeyBackendSync, s.Name()), 0, nbItem, &itemIDs); err != nil {
2424
return err
2525
}
26-
log.Info(ctx, "FillSyncItemChannel> Item to sync for %s: %d", s.Name(), len(itemIDs))
26+
if len(itemIDs) > 0 {
27+
log.Info(ctx, "FillSyncItemChannel> Item to sync for %s: %d", s.Name(), len(itemIDs))
28+
}
2729
for _, id := range itemIDs {
2830
select {
2931
case s.SyncItemChannel() <- id:

sdk/cdsclient/client_project_variable.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,11 @@ func (c *client) VariableEncrypt(projectKey string, varName string, content stri
4949
}
5050
return variable, nil
5151
}
52+
53+
func (c *client) VariableListEncrypt(projectKey string) ([]sdk.Secret, error) {
54+
secrets := []sdk.Secret{}
55+
if _, err := c.GetJSON(context.Background(), "/project/"+projectKey+"/encrypt/list", &secrets, nil); err != nil {
56+
return nil, err
57+
}
58+
return secrets, nil
59+
}

sdk/cdsclient/interface.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ type ProjectVariablesClient interface {
241241
ProjectVariableGet(projectKey string, varName string) (*sdk.Variable, error)
242242
ProjectVariableUpdate(projectKey string, variable *sdk.Variable) error
243243
VariableEncrypt(projectKey string, varName string, content string) (*sdk.Variable, error)
244+
VariableListEncrypt(projectKey string) ([]sdk.Secret, error)
244245
}
245246

246247
// QueueClient exposes queue related functions

sdk/cdsclient/mock_cdsclient/interface_mock.go

Lines changed: 49 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sdk/variable.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ import (
66
"time"
77
)
88

9+
type Secret struct {
10+
ProjectID int64 `json:"project_id" db:"project_id" cli:"-"`
11+
Name string `json:"name" db:"content_name" cli:"name,key"`
12+
Token string `json:"token" db:"token" cli:"token"`
13+
Status string `json:"status" db:"-" cli:"status"`
14+
}
15+
916
// Variable represent a variable for a project or pipeline
1017
type Variable struct {
1118
ID int64 `json:"id,omitempty" cli:"-"`

0 commit comments

Comments
 (0)