Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import (
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/locksutil"
"github.com/hashicorp/vault/sdk/logical"

"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags"
g "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab"
"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils"
)

const (
Expand All @@ -27,14 +31,14 @@ with the "^config/(?P<config_name>\w(([\w-.@]+)?\w)?)$" endpoints.
`
)

func Factory(flags Flags) logical.Factory {
func Factory(flags flags.Flags) logical.Factory {
return func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) {
return factory(ctx, config, flags)
}
}

// Factory returns expected new Backend as logical.Backend
func factory(ctx context.Context, conf *logical.BackendConfig, flags Flags) (logical.Backend, error) {
func factory(ctx context.Context, conf *logical.BackendConfig, flags flags.Flags) (logical.Backend, error) {
var b = &Backend{
roleLocks: locksutil.CreateLocks(),
clients: sync.Map{},
Expand Down Expand Up @@ -82,7 +86,7 @@ func factory(ctx context.Context, conf *logical.BackendConfig, flags Flags) (log
type Backend struct {
*framework.Backend

flags Flags
flags flags.Flags

// The client that we can use to create and revoke the access tokens
clients sync.Map
Expand Down Expand Up @@ -180,8 +184,8 @@ func (b *Backend) getClient(ctx context.Context, s logical.Storage, name string)
}

var httpClient *http.Client
httpClient, _ = HttpClientFromContext(ctx)
if client, _ = ClientFromContext(ctx); client == nil {
httpClient, _ = utils.HttpClientFromContext(ctx)
if client, _ = g.ClientFromContext(ctx); client == nil {
if client, err = NewGitlabClient(config, httpClient, b.Logger()); err == nil {
b.SetClient(client, name)
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/vault-plugin-secrets-gitlab/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/hashicorp/vault/sdk/plugin"

gat "github.com/ilijamt/vault-plugin-secrets-gitlab"
f "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags"
)

var (
Expand All @@ -17,7 +18,7 @@ var (
func main() {
apiClientMeta := &api.PluginAPIClientMeta{}
flags := apiClientMeta.FlagSet()
pf := &gat.Flags{}
pf := &f.Flags{}
pf.FlagSet(flags)

fatalIfError(flags.Parse(os.Args[1:]))
Expand Down
52 changes: 0 additions & 52 deletions defs.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
package gitlab

import (
"context"
"errors"
"net/http"
"time"
)

var (
ErrNilValue = errors.New("nil value")
ErrInvalidValue = errors.New("invalid value")
ErrFieldRequired = errors.New("required field")
ErrFieldInvalidValue = errors.New("invalid value for field")
ErrBackendNotConfigured = errors.New("backend not configured")
)

type contextKey string

const (
DefaultConfigFieldAccessTokenMaxTTL = 7 * 24 * time.Hour
DefaultConfigFieldAccessTokenRotate = DefaultAutoRotateBeforeMinTTL
Expand All @@ -25,44 +12,5 @@ const (
DefaultAccessTokenMaxPossibleTTL = 365 * 24 * time.Hour
DefaultAutoRotateBeforeMinTTL = 24 * time.Hour
DefaultAutoRotateBeforeMaxTTL = 730 * time.Hour
ctxKeyHttpClient = contextKey("vpsg-ctx-key-http-client")
ctxKeyGitlabClient = contextKey("vpsg-ctx-key-gitlab-client")
ctxKeyTimeNow = contextKey("vpsg-ctx-key-time-now")
DefaultConfigName = "default"
)

func WithStaticTime(ctx context.Context, t time.Time) context.Context {
return context.WithValue(ctx, ctxKeyTimeNow, t)
}

func TimeFromContext(ctx context.Context) time.Time {
t, ok := ctx.Value(ctxKeyTimeNow).(time.Time)
if !ok {
return time.Now()
}
return t
}

func HttpClientNewContext(ctx context.Context, httpClient *http.Client) context.Context {
return context.WithValue(ctx, ctxKeyHttpClient, httpClient)
}

func HttpClientFromContext(ctx context.Context) (*http.Client, bool) {
u, ok := ctx.Value(ctxKeyHttpClient).(*http.Client)
if !ok {
u = nil
}
return u, ok
}

func ClientNewContext(ctx context.Context, client Client) context.Context {
return context.WithValue(ctx, ctxKeyGitlabClient, client)
}

func ClientFromContext(ctx context.Context) (Client, bool) {
u, ok := ctx.Value(ctxKeyGitlabClient).(Client)
if !ok {
u = nil
}
return u, ok
}
30 changes: 17 additions & 13 deletions entry_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import (
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"

"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs"
"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab"
"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils"
)

type EntryConfig struct {
Expand All @@ -22,7 +26,7 @@ type EntryConfig struct {
TokenCreatedAt time.Time `json:"token_created_at" structs:"token_created_at" mapstructure:"token_created_at"`
TokenExpiresAt time.Time `json:"token_expires_at" structs:"token_expires_at" mapstructure:"token_expires_at"`
Scopes []string `json:"scopes" structs:"scopes" mapstructure:"scopes"`
Type Type `json:"type" structs:"type" mapstructure:"type"`
Type gitlab.Type `json:"type" structs:"type" mapstructure:"type"`
Name string `json:"name" structs:"name" mapstructure:"name"`
GitlabVersion string `json:"gitlab_version" structs:"gitlab_version" mapstructure:"gitlab_version"`
GitlabRevision string `json:"gitlab_revision" structs:"gitlab_revision" mapstructure:"gitlab_revision"`
Expand All @@ -32,7 +36,7 @@ type EntryConfig struct {
func (e *EntryConfig) Merge(data *framework.FieldData) (warnings []string, changes map[string]string, err error) {
var er error
if data == nil {
return warnings, changes, multierror.Append(fmt.Errorf("data: %w", ErrNilValue))
return warnings, changes, multierror.Append(fmt.Errorf("data: %w", errs.ErrNilValue))
}

if err = data.Validate(); err != nil {
Expand All @@ -47,8 +51,8 @@ func (e *EntryConfig) Merge(data *framework.FieldData) (warnings []string, chang
}

if typ, ok := data.GetOk("type"); ok {
var pType Type
if pType, er = TypeParse(typ.(string)); er != nil {
var pType gitlab.Type
if pType, er = gitlab.TypeParse(typ.(string)); er != nil {
err = multierror.Append(err, er)
} else {
e.Type = pType
Expand Down Expand Up @@ -81,11 +85,11 @@ func (e *EntryConfig) Merge(data *framework.FieldData) (warnings []string, chang

func (e *EntryConfig) updateAutoRotateBefore(data *framework.FieldData) (warnings []string, err *multierror.Error) {
if val, ok := data.GetOk("auto_rotate_before"); ok {
atr, _ := convertToInt(val)
atr, _ := utils.ConvertToInt(val)
if atr > int(DefaultAutoRotateBeforeMaxTTL.Seconds()) {
err = multierror.Append(err, fmt.Errorf("auto_rotate_token can not be bigger than %s: %w", DefaultAutoRotateBeforeMaxTTL, ErrInvalidValue))
err = multierror.Append(err, fmt.Errorf("auto_rotate_token can not be bigger than %s: %w", DefaultAutoRotateBeforeMaxTTL, errs.ErrInvalidValue))
} else if atr <= int(DefaultAutoRotateBeforeMinTTL.Seconds())-1 {
err = multierror.Append(err, fmt.Errorf("auto_rotate_token can not be less than %s: %w", DefaultAutoRotateBeforeMinTTL, ErrInvalidValue))
err = multierror.Append(err, fmt.Errorf("auto_rotate_token can not be less than %s: %w", DefaultAutoRotateBeforeMinTTL, errs.ErrInvalidValue))
} else {
e.AutoRotateBefore = time.Duration(atr) * time.Second
}
Expand All @@ -98,7 +102,7 @@ func (e *EntryConfig) updateAutoRotateBefore(data *framework.FieldData) (warning

func (e *EntryConfig) UpdateFromFieldData(data *framework.FieldData) (warnings []string, err error) {
if data == nil {
return warnings, multierror.Append(fmt.Errorf("data: %w", ErrNilValue))
return warnings, multierror.Append(fmt.Errorf("data: %w", errs.ErrNilValue))
}

if err = data.Validate(); err != nil {
Expand All @@ -111,21 +115,21 @@ func (e *EntryConfig) UpdateFromFieldData(data *framework.FieldData) (warnings [
if token, ok := data.GetOk("token"); ok && len(token.(string)) > 0 {
e.Token = token.(string)
} else {
err = multierror.Append(err, fmt.Errorf("token: %w", ErrFieldRequired))
err = multierror.Append(err, fmt.Errorf("token: %w", errs.ErrFieldRequired))
}

if typ, ok := data.GetOk("type"); ok {
if e.Type, er = TypeParse(typ.(string)); er != nil {
if e.Type, er = gitlab.TypeParse(typ.(string)); er != nil {
err = multierror.Append(err, er)
}
} else {
err = multierror.Append(err, fmt.Errorf("gitlab type: %w", ErrFieldRequired))
err = multierror.Append(err, fmt.Errorf("gitlab type: %w", errs.ErrFieldRequired))
}

if baseUrl, ok := data.GetOk("base_url"); ok && len(baseUrl.(string)) > 0 {
e.BaseURL = baseUrl.(string)
} else {
err = multierror.Append(err, fmt.Errorf("base_url: %w", ErrFieldRequired))
err = multierror.Append(err, fmt.Errorf("base_url: %w", errs.ErrFieldRequired))
}

{
Expand Down Expand Up @@ -173,7 +177,7 @@ func (e *EntryConfig) LogicalResponseData(includeToken bool) (data map[string]an

func getConfig(ctx context.Context, s logical.Storage, name string) (cfg *EntryConfig, err error) {
if s == nil {
return nil, fmt.Errorf("%w: local.Storage", ErrNilValue)
return nil, fmt.Errorf("%w: local.Storage", errs.ErrNilValue)
}
var entry *logical.StorageEntry
if entry, err = s.Get(ctx, fmt.Sprintf("%s/%s", PathConfigStorage, name)); err == nil {
Expand Down
22 changes: 12 additions & 10 deletions entry_config_merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/stretchr/testify/require"

gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab"
"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs"
gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab"
)

func TestEntryConfigMerge(t *testing.T) {
Expand All @@ -20,7 +22,7 @@ func TestEntryConfigMerge(t *testing.T) {
warnings, changes, err := e.Merge(nil)
require.Empty(t, warnings)
require.Empty(t, changes)
require.ErrorIs(t, err, gitlab.ErrNilValue)
require.ErrorIs(t, err, errs.ErrNilValue)
})

t.Run("unconvertible data type", func(t *testing.T) {
Expand All @@ -46,10 +48,10 @@ func TestEntryConfigMerge(t *testing.T) {
}{
{
name: "update type only",
originalConfig: &gitlab.EntryConfig{Type: gitlab.TypeSelfManaged},
expectedConfig: &gitlab.EntryConfig{Type: gitlab.TypeSaaS},
raw: map[string]interface{}{"type": gitlab.TypeSaaS},
changes: map[string]string{"type": gitlab.TypeSaaS.String()},
originalConfig: &gitlab.EntryConfig{Type: gitlab2.TypeSelfManaged},
expectedConfig: &gitlab.EntryConfig{Type: gitlab2.TypeSaaS},
raw: map[string]interface{}{"type": gitlab2.TypeSaaS},
changes: map[string]string{"type": gitlab2.TypeSaaS.String()},
},
{
name: "auto rotate token set to false",
Expand All @@ -67,12 +69,12 @@ func TestEntryConfigMerge(t *testing.T) {
},
{
name: "update type with invalid type",
originalConfig: &gitlab.EntryConfig{Type: gitlab.TypeSelfManaged},
expectedConfig: &gitlab.EntryConfig{Type: gitlab.TypeSelfManaged},
originalConfig: &gitlab.EntryConfig{Type: gitlab2.TypeSelfManaged},
expectedConfig: &gitlab.EntryConfig{Type: gitlab2.TypeSelfManaged},
raw: map[string]interface{}{"type": "test"},
err: true,
errMap: map[string]int{
gitlab.ErrUnknownType.Error(): 1,
gitlab2.ErrUnknownType.Error(): 1,
},
},
{
Expand All @@ -95,15 +97,15 @@ func TestEntryConfigMerge(t *testing.T) {
expectedConfig: &gitlab.EntryConfig{AutoRotateBefore: gitlab.DefaultAutoRotateBeforeMinTTL + time.Hour},
raw: map[string]interface{}{"auto_rotate_before": "1h"},
err: true,
errMap: map[string]int{gitlab.ErrInvalidValue.Error(): 1},
errMap: map[string]int{errs.ErrInvalidValue.Error(): 1},
},
{
name: "auto rotate before invalid value higher than min",
originalConfig: &gitlab.EntryConfig{AutoRotateBefore: gitlab.DefaultAutoRotateBeforeMinTTL + time.Hour},
expectedConfig: &gitlab.EntryConfig{AutoRotateBefore: gitlab.DefaultAutoRotateBeforeMinTTL + time.Hour},
raw: map[string]interface{}{"auto_rotate_before": (gitlab.DefaultAutoRotateBeforeMaxTTL + time.Hour).String()},
err: true,
errMap: map[string]int{gitlab.ErrInvalidValue.Error(): 1},
errMap: map[string]int{errs.ErrInvalidValue.Error(): 1},
},
{
name: "auto rotate with a valid value",
Expand Down
14 changes: 8 additions & 6 deletions entry_config_update_form_field_data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import (
"github.com/stretchr/testify/require"

gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab"
"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs"
gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab"
)

func TestEntryConfigUpdateFromFieldData(t *testing.T) {
t.Run("nil data", func(t *testing.T) {
e := new(gitlab.EntryConfig)
_, err := e.UpdateFromFieldData(nil)
require.ErrorIs(t, err, gitlab.ErrNilValue)
require.ErrorIs(t, err, errs.ErrNilValue)
})

var tests = []struct {
Expand All @@ -34,7 +36,7 @@ func TestEntryConfigUpdateFromFieldData(t *testing.T) {
err: true,
warnings: []string{"auto_rotate_token not specified setting to 24h0m0s"},
errMap: map[string]int{
gitlab.ErrFieldRequired.Error(): 3,
errs.ErrFieldRequired.Error(): 3,
},
},
{
Expand All @@ -47,8 +49,8 @@ func TestEntryConfigUpdateFromFieldData(t *testing.T) {
warnings: []string{"auto_rotate_token not specified setting to 24h0m0s"},
err: true,
errMap: map[string]int{
gitlab.ErrFieldRequired.Error(): 1,
gitlab.ErrUnknownType.Error(): 1,
errs.ErrFieldRequired.Error(): 1,
gitlab2.ErrUnknownType.Error(): 1,
},
},
{
Expand All @@ -64,15 +66,15 @@ func TestEntryConfigUpdateFromFieldData(t *testing.T) {
name: "valid config",
expectedConfig: &gitlab.EntryConfig{
Token: "token",
Type: gitlab.TypeSelfManaged,
Type: gitlab2.TypeSelfManaged,
AutoRotateToken: false,
AutoRotateBefore: gitlab.DefaultAutoRotateBeforeMinTTL,
BaseURL: "https://gitlab.com",
},
warnings: []string{"auto_rotate_token not specified setting to 24h0m0s"},
raw: map[string]interface{}{
"token": "token",
"type": gitlab.TypeSelfManaged.String(),
"type": gitlab2.TypeSelfManaged.String(),
"base_url": "https://gitlab.com",
},
},
Expand Down
28 changes: 19 additions & 9 deletions entry_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,28 @@ import (
"time"

"github.com/hashicorp/vault/sdk/logical"

"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token"
)

type EntryRole struct {
RoleName string `json:"role_name" structs:"role_name" mapstructure:"role_name"`
TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl"`
Path string `json:"path" structs:"path" mapstructure:"path"`
Name string `json:"name" structs:"name" mapstructure:"name"`
Scopes []string `json:"scopes" structs:"scopes" mapstructure:"scopes"`
AccessLevel AccessLevel `json:"access_level" structs:"access_level" mapstructure:"access_level,omitempty"`
TokenType TokenType `json:"token_type" structs:"token_type" mapstructure:"token_type"`
GitlabRevokesTokens bool `json:"gitlab_revokes_token" structs:"gitlab_revokes_token" mapstructure:"gitlab_revokes_token"`
ConfigName string `json:"config_name" structs:"config_name" mapstructure:"config_name"`
RoleName string `json:"role_name" structs:"role_name" mapstructure:"role_name"`
TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl"`
Path string `json:"path" structs:"path" mapstructure:"path"`
Name string `json:"name" structs:"name" mapstructure:"name"`
Scopes []string `json:"scopes" structs:"scopes" mapstructure:"scopes"`
AccessLevel token.AccessLevel `json:"access_level" structs:"access_level" mapstructure:"access_level,omitempty"`
TokenType token.Type `json:"token_type" structs:"token_type" mapstructure:"token_type"`
GitlabRevokesTokens bool `json:"gitlab_revokes_token" structs:"gitlab_revokes_token" mapstructure:"gitlab_revokes_token"`
ConfigName string `json:"config_name" structs:"config_name" mapstructure:"config_name"`
}

func (e EntryRole) IsNil() bool {
return false
}

func (e EntryRole) GetName() string {
return e.Name
}

func (e EntryRole) LogicalResponseData() map[string]any {
Expand Down
Loading