All checks were successful
Build and Release / Create Release (push) Successful in 0s
Build and Release / Unit Tests (push) Successful in 3m5s
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 4m44s
Build and Release / Lint (push) Successful in 5m5s
Build and Release / Build Binaries (amd64, darwin, linux-latest) (push) Successful in 2m51s
Build and Release / Build Binaries (arm64, darwin, linux-latest) (push) Successful in 3m42s
Build and Release / Build Binaries (amd64, linux, linux-latest) (push) Successful in 4m1s
Build and Release / Build Binaries (arm64, linux, linux-latest) (push) Successful in 4m6s
Build and Release / Build Binaries (amd64, windows, windows-latest) (push) Successful in 9h4m37s
- Solo tier changes: - 2 versions history (limited rollback capability) - 1 CI/CD token (24h max TTL, read-only access) - SSO remains Pro+ only - Added granular license limits: - MaxVersions, MaxTokens, MaxTokenTTLHours, TokensReadOnly - Added token limit enforcement with CheckTokenLimit() - Updated all 28 locale files with new translations - Added templates: - feature_upgrade.tmpl (for SSO upgrade prompts) - not_installed.tmpl (when vault plugin missing) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
185 lines
5.3 KiB
Go
185 lines
5.3 KiB
Go
// Copyright 2026 MarketAlly. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package plugins
|
|
|
|
import (
|
|
"context"
|
|
|
|
"xorm.io/xorm"
|
|
)
|
|
|
|
// Plugin defines the interface that all GitCaddy plugins must implement
|
|
type Plugin interface {
|
|
// Name returns the unique identifier for this plugin
|
|
Name() string
|
|
|
|
// Version returns the plugin version
|
|
Version() string
|
|
|
|
// Description returns a human-readable description
|
|
Description() string
|
|
|
|
// Init is called when the plugin is loaded
|
|
Init(ctx context.Context) error
|
|
|
|
// Shutdown is called when the server is shutting down
|
|
Shutdown(ctx context.Context) error
|
|
}
|
|
|
|
// DatabasePlugin is implemented by plugins that need database tables
|
|
type DatabasePlugin interface {
|
|
Plugin
|
|
|
|
// RegisterModels returns the models to be registered with the database
|
|
RegisterModels() []any
|
|
|
|
// Migrate runs any database migrations for this plugin
|
|
Migrate(ctx context.Context, x *xorm.Engine) error
|
|
}
|
|
|
|
// WebRoutesPlugin is implemented by plugins that add web UI routes
|
|
type WebRoutesPlugin interface {
|
|
Plugin
|
|
|
|
// RegisterWebRoutes adds routes to the web UI router
|
|
// The router is a *web.Router from the gitcaddy server
|
|
RegisterWebRoutes(m any)
|
|
}
|
|
|
|
// APIRoutesPlugin is implemented by plugins that add API routes
|
|
type APIRoutesPlugin interface {
|
|
Plugin
|
|
|
|
// RegisterAPIRoutes adds routes to the API router
|
|
// The router is a *web.Router from the gitcaddy server
|
|
RegisterAPIRoutes(m any)
|
|
}
|
|
|
|
// RepoRoutesPlugin is implemented by plugins that add per-repository routes
|
|
type RepoRoutesPlugin interface {
|
|
Plugin
|
|
|
|
// RegisterRepoWebRoutes adds routes under /{owner}/{repo}/
|
|
// The router is a *web.Router from the gitcaddy server
|
|
RegisterRepoWebRoutes(m any)
|
|
|
|
// RegisterRepoAPIRoutes adds routes under /api/v1/repos/{owner}/{repo}/
|
|
// The router is a *web.Router from the gitcaddy server
|
|
RegisterRepoAPIRoutes(m any)
|
|
}
|
|
|
|
// LicensedPlugin is implemented by plugins that require a license
|
|
type LicensedPlugin interface {
|
|
Plugin
|
|
|
|
// ValidateLicense checks if the plugin is properly licensed
|
|
ValidateLicense(ctx context.Context) error
|
|
|
|
// LicenseInfo returns information about the current license
|
|
LicenseInfo() *LicenseInfo
|
|
}
|
|
|
|
// License tier constants
|
|
const (
|
|
TierSolo = "solo"
|
|
TierPro = "pro"
|
|
TierTeam = "team"
|
|
TierEnterprise = "enterprise"
|
|
)
|
|
|
|
// LicenseInfo contains license details
|
|
type LicenseInfo struct {
|
|
Valid bool
|
|
Tier string // e.g., "solo", "pro", "team", "enterprise"
|
|
CustomerID string
|
|
ExpiresAt int64
|
|
GracePeriod bool // true if in grace period after expiry
|
|
}
|
|
|
|
// LicenseLimits defines the limits for each tier
|
|
type LicenseLimits struct {
|
|
Users int // Max users with vault access (-1 = unlimited)
|
|
SecretsPerRepo int // Max secrets per repo (-1 = unlimited)
|
|
AuditRetentionDays int // Days to keep audit logs
|
|
VersioningEnabled bool // Can use secret versioning/rollback
|
|
MaxVersions int // Max versions to keep per secret (-1 = unlimited, 0 = disabled)
|
|
CICDTokensEnabled bool // Can create CI/CD tokens
|
|
MaxTokens int // Max CI/CD tokens per repo (-1 = unlimited, 0 = disabled)
|
|
MaxTokenTTLHours int // Max token TTL in hours (-1 = unlimited)
|
|
TokensReadOnly bool // If true, tokens can only read secrets (not write)
|
|
SSOEnabled bool // Can use SSO/SAML
|
|
}
|
|
|
|
// DefaultSoloLicense returns the default Solo tier license (free, no registration required)
|
|
func DefaultSoloLicense() *LicenseInfo {
|
|
return &LicenseInfo{
|
|
Valid: true,
|
|
Tier: TierSolo,
|
|
CustomerID: "",
|
|
ExpiresAt: 0, // Never expires
|
|
GracePeriod: false,
|
|
}
|
|
}
|
|
|
|
// GetLimitsForTier returns the limits for a given license tier
|
|
func GetLimitsForTier(tier string) *LicenseLimits {
|
|
switch tier {
|
|
case TierSolo:
|
|
return &LicenseLimits{
|
|
Users: 1,
|
|
SecretsPerRepo: 5,
|
|
AuditRetentionDays: 7,
|
|
VersioningEnabled: true, // Limited versioning
|
|
MaxVersions: 2, // Keep last 2 versions only
|
|
CICDTokensEnabled: true, // Limited CI/CD
|
|
MaxTokens: 1, // 1 token only
|
|
MaxTokenTTLHours: 24, // Max 24h TTL
|
|
TokensReadOnly: true, // Read-only access
|
|
SSOEnabled: false,
|
|
}
|
|
case TierPro:
|
|
return &LicenseLimits{
|
|
Users: 5,
|
|
SecretsPerRepo: -1, // Unlimited
|
|
AuditRetentionDays: 90,
|
|
VersioningEnabled: true,
|
|
MaxVersions: -1, // Unlimited
|
|
CICDTokensEnabled: true,
|
|
MaxTokens: -1, // Unlimited
|
|
MaxTokenTTLHours: -1, // Unlimited
|
|
TokensReadOnly: false,
|
|
SSOEnabled: false,
|
|
}
|
|
case TierTeam:
|
|
return &LicenseLimits{
|
|
Users: 25,
|
|
SecretsPerRepo: -1, // Unlimited
|
|
AuditRetentionDays: 365,
|
|
VersioningEnabled: true,
|
|
MaxVersions: -1, // Unlimited
|
|
CICDTokensEnabled: true,
|
|
MaxTokens: -1, // Unlimited
|
|
MaxTokenTTLHours: -1, // Unlimited
|
|
TokensReadOnly: false,
|
|
SSOEnabled: true,
|
|
}
|
|
case TierEnterprise:
|
|
return &LicenseLimits{
|
|
Users: -1, // Unlimited
|
|
SecretsPerRepo: -1, // Unlimited
|
|
AuditRetentionDays: -1, // Custom/unlimited
|
|
VersioningEnabled: true,
|
|
MaxVersions: -1, // Unlimited
|
|
CICDTokensEnabled: true,
|
|
MaxTokens: -1, // Unlimited
|
|
MaxTokenTTLHours: -1, // Unlimited
|
|
TokensReadOnly: false,
|
|
SSOEnabled: true,
|
|
}
|
|
default:
|
|
// Unknown tier defaults to Solo limits
|
|
return GetLimitsForTier(TierSolo)
|
|
}
|
|
}
|