Add license limit enforcement when creating secrets and tokens. Pass license limits to service layer and return appropriate errors when tier limits are exceeded. Handle limit errors in both API and web routes with proper error messages prompting users to upgrade.
294 lines
8.8 KiB
Go
294 lines
8.8 KiB
Go
// Copyright 2026 MarketAlly. All rights reserved.
|
|
// Business Source License 1.1 - See LICENSE file for details.
|
|
|
|
package vault
|
|
|
|
import (
|
|
"context"
|
|
|
|
"git.marketally.com/gitcaddy/gitcaddy-vault/services"
|
|
|
|
vault_service "code.gitcaddy.com/server/v3/services/vault"
|
|
)
|
|
|
|
// Ensure VaultPlugin implements the vault service Plugin interface
|
|
var _ vault_service.Plugin = (*VaultPlugin)(nil)
|
|
|
|
// ListSecrets lists all secrets for a repository
|
|
func (p *VaultPlugin) ListSecrets(ctx context.Context, repoID int64, includeDeleted bool) ([]vault_service.Secret, error) {
|
|
secrets, err := services.ListSecrets(ctx, repoID, includeDeleted)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make([]vault_service.Secret, len(secrets))
|
|
for i, s := range secrets {
|
|
result[i] = vault_service.Secret{
|
|
ID: s.ID,
|
|
RepoID: s.RepoID,
|
|
Name: s.Name,
|
|
Description: s.Description,
|
|
Type: string(s.Type),
|
|
CurrentVersion: s.CurrentVersion,
|
|
CreatedUnix: int64(s.CreatedUnix),
|
|
UpdatedUnix: int64(s.UpdatedUnix),
|
|
DeletedUnix: int64(s.DeletedUnix),
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// GetSecret returns a secret by name
|
|
func (p *VaultPlugin) GetSecret(ctx context.Context, repoID int64, name string) (*vault_service.Secret, error) {
|
|
s, err := services.GetSecret(ctx, repoID, name)
|
|
if err != nil {
|
|
if err == services.ErrSecretNotFound {
|
|
return nil, vault_service.ErrSecretNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
return &vault_service.Secret{
|
|
ID: s.ID,
|
|
RepoID: s.RepoID,
|
|
Name: s.Name,
|
|
Description: s.Description,
|
|
Type: string(s.Type),
|
|
CurrentVersion: s.CurrentVersion,
|
|
CreatedUnix: int64(s.CreatedUnix),
|
|
UpdatedUnix: int64(s.UpdatedUnix),
|
|
DeletedUnix: int64(s.DeletedUnix),
|
|
}, nil
|
|
}
|
|
|
|
// GetSecretValue returns the decrypted value of a secret
|
|
func (p *VaultPlugin) GetSecretValue(ctx context.Context, repoID int64, name string, version int) (string, error) {
|
|
return services.GetSecretValue(ctx, repoID, name, version)
|
|
}
|
|
|
|
// CreateSecret creates a new secret
|
|
func (p *VaultPlugin) CreateSecret(ctx context.Context, repoID int64, opts vault_service.CreateSecretOptions) (*vault_service.Secret, error) {
|
|
s, err := services.CreateSecret(ctx, repoID, services.CreateSecretOptions{
|
|
Name: opts.Name,
|
|
Description: opts.Description,
|
|
Type: opts.Type,
|
|
Value: opts.Value,
|
|
CreatorID: opts.CreatorID,
|
|
}, nil)
|
|
if err != nil {
|
|
if err == services.ErrSecretExists {
|
|
return nil, vault_service.ErrSecretExists
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
return &vault_service.Secret{
|
|
ID: s.ID,
|
|
RepoID: s.RepoID,
|
|
Name: s.Name,
|
|
Description: s.Description,
|
|
Type: string(s.Type),
|
|
CurrentVersion: s.CurrentVersion,
|
|
CreatedUnix: int64(s.CreatedUnix),
|
|
UpdatedUnix: int64(s.UpdatedUnix),
|
|
DeletedUnix: int64(s.DeletedUnix),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateSecret updates an existing secret
|
|
func (p *VaultPlugin) UpdateSecret(ctx context.Context, repoID int64, name string, opts vault_service.UpdateSecretOptions) (*vault_service.Secret, error) {
|
|
s, err := services.UpdateSecret(ctx, repoID, name, services.UpdateSecretOptions{
|
|
Type: opts.Type,
|
|
Value: opts.Value,
|
|
Comment: opts.Comment,
|
|
UpdaterID: opts.UpdaterID,
|
|
})
|
|
if err != nil {
|
|
if err == services.ErrSecretNotFound {
|
|
return nil, vault_service.ErrSecretNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
return &vault_service.Secret{
|
|
ID: s.ID,
|
|
RepoID: s.RepoID,
|
|
Name: s.Name,
|
|
Description: s.Description,
|
|
Type: string(s.Type),
|
|
CurrentVersion: s.CurrentVersion,
|
|
CreatedUnix: int64(s.CreatedUnix),
|
|
UpdatedUnix: int64(s.UpdatedUnix),
|
|
DeletedUnix: int64(s.DeletedUnix),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteSecret soft-deletes a secret
|
|
func (p *VaultPlugin) DeleteSecret(ctx context.Context, repoID int64, name string, userID int64) error {
|
|
err := services.DeleteSecret(ctx, repoID, name, userID)
|
|
if err == services.ErrSecretNotFound {
|
|
return vault_service.ErrSecretNotFound
|
|
}
|
|
return err
|
|
}
|
|
|
|
// RestoreSecret restores a soft-deleted secret
|
|
func (p *VaultPlugin) RestoreSecret(ctx context.Context, repoID int64, name string) error {
|
|
err := services.RestoreSecret(ctx, repoID, name)
|
|
if err == services.ErrSecretNotFound {
|
|
return vault_service.ErrSecretNotFound
|
|
}
|
|
return err
|
|
}
|
|
|
|
// RollbackSecret rolls back a secret to a previous version
|
|
func (p *VaultPlugin) RollbackSecret(ctx context.Context, repoID int64, name string, version int, userID int64) error {
|
|
err := services.RollbackSecret(ctx, repoID, name, version, userID)
|
|
if err == services.ErrSecretNotFound {
|
|
return vault_service.ErrSecretNotFound
|
|
}
|
|
if err == services.ErrVersionNotFound {
|
|
return vault_service.ErrSecretNotFound // Map to generic not found
|
|
}
|
|
return err
|
|
}
|
|
|
|
// ListVersions lists all versions of a secret
|
|
func (p *VaultPlugin) ListVersions(ctx context.Context, repoID int64, name string) ([]vault_service.SecretVersion, error) {
|
|
versions, err := services.ListVersions(ctx, repoID, name)
|
|
if err != nil {
|
|
if err == services.ErrSecretNotFound {
|
|
return nil, vault_service.ErrSecretNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
result := make([]vault_service.SecretVersion, len(versions))
|
|
for i, v := range versions {
|
|
result[i] = vault_service.SecretVersion{
|
|
ID: v.ID,
|
|
SecretID: v.SecretID,
|
|
Version: v.Version,
|
|
CreatorID: v.CreatedBy,
|
|
Comment: v.Comment,
|
|
CreatedUnix: int64(v.CreatedUnix),
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// ListTokens lists all tokens for a repository
|
|
func (p *VaultPlugin) ListTokens(ctx context.Context, repoID int64) ([]vault_service.Token, error) {
|
|
tokens, err := services.ListTokens(ctx, repoID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make([]vault_service.Token, len(tokens))
|
|
for i, t := range tokens {
|
|
result[i] = vault_service.Token{
|
|
ID: t.ID,
|
|
RepoID: t.RepoID,
|
|
Description: t.Description,
|
|
Scope: string(t.Scope),
|
|
CreatedUnix: int64(t.CreatedUnix),
|
|
ExpiresUnix: int64(t.ExpiresUnix),
|
|
LastUsedUnix: int64(t.LastUsedUnix),
|
|
UsedCount: t.UsedCount,
|
|
IsRevoked: t.IsRevoked(),
|
|
IsExpired: t.IsExpired(),
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// CreateToken creates a new CI/CD token
|
|
func (p *VaultPlugin) CreateToken(ctx context.Context, repoID int64, opts vault_service.CreateTokenOptions) (*vault_service.Token, string, error) {
|
|
t, rawToken, err := services.CreateToken(ctx, repoID, services.CreateTokenOptions{
|
|
Description: opts.Description,
|
|
Scope: opts.Scope,
|
|
TTL: opts.TTL,
|
|
CreatorID: opts.CreatorID,
|
|
}, nil)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
return &vault_service.Token{
|
|
ID: t.ID,
|
|
RepoID: t.RepoID,
|
|
Description: t.Description,
|
|
Scope: string(t.Scope),
|
|
CreatedUnix: int64(t.CreatedUnix),
|
|
ExpiresUnix: int64(t.ExpiresUnix),
|
|
LastUsedUnix: int64(t.LastUsedUnix),
|
|
UsedCount: t.UsedCount,
|
|
IsRevoked: t.IsRevoked(),
|
|
IsExpired: t.IsExpired(),
|
|
}, rawToken, nil
|
|
}
|
|
|
|
// RevokeToken revokes a token
|
|
func (p *VaultPlugin) RevokeToken(ctx context.Context, repoID, tokenID int64) error {
|
|
err := services.RevokeToken(ctx, repoID, tokenID)
|
|
if err == services.ErrTokenNotFound {
|
|
return vault_service.ErrTokenNotFound
|
|
}
|
|
return err
|
|
}
|
|
|
|
// ValidateToken validates a token for a specific action
|
|
func (p *VaultPlugin) ValidateToken(ctx context.Context, rawToken, action, secretName string) (*vault_service.Token, error) {
|
|
t, err := services.ValidateToken(ctx, rawToken, action, secretName)
|
|
if err != nil {
|
|
switch err {
|
|
case services.ErrTokenNotFound, services.ErrInvalidToken:
|
|
return nil, vault_service.ErrInvalidToken
|
|
case services.ErrTokenExpired:
|
|
return nil, vault_service.ErrTokenExpired
|
|
case services.ErrTokenRevoked:
|
|
return nil, vault_service.ErrTokenNotFound
|
|
case services.ErrAccessDenied:
|
|
return nil, vault_service.ErrAccessDenied
|
|
default:
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return &vault_service.Token{
|
|
ID: t.ID,
|
|
RepoID: t.RepoID,
|
|
Description: t.Description,
|
|
Scope: string(t.Scope),
|
|
CreatedUnix: int64(t.CreatedUnix),
|
|
ExpiresUnix: int64(t.ExpiresUnix),
|
|
LastUsedUnix: int64(t.LastUsedUnix),
|
|
UsedCount: t.UsedCount,
|
|
IsRevoked: t.IsRevoked(),
|
|
IsExpired: t.IsExpired(),
|
|
}, nil
|
|
}
|
|
|
|
// ListAuditEntries lists audit entries for a repository
|
|
func (p *VaultPlugin) ListAuditEntries(ctx context.Context, repoID int64, page, pageSize int) ([]vault_service.AuditEntry, int64, error) {
|
|
entries, total, err := services.ListAuditEntries(ctx, repoID, page, pageSize)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
result := make([]vault_service.AuditEntry, len(entries))
|
|
for i, e := range entries {
|
|
result[i] = vault_service.AuditEntry{
|
|
ID: e.ID,
|
|
RepoID: e.RepoID,
|
|
Action: string(e.Action),
|
|
UserID: e.UserID,
|
|
IPAddress: e.IPAddress,
|
|
Success: e.Success,
|
|
FailReason: e.FailReason,
|
|
Timestamp: int64(e.Timestamp),
|
|
}
|
|
}
|
|
return result, total, nil
|
|
}
|