2
0
Files
logikonline 6790c1ea7c feat(license): enforce tier limits for secrets and tokens
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.
2026-01-21 15:55:29 -05:00

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
}