chore: refactor license validation (#20411)

This commit is contained in:
Marcin Tojek
2025-10-22 16:12:36 +02:00
committed by GitHub
parent 823b14aa34
commit caeca1097b
3 changed files with 65 additions and 3 deletions
@@ -186,6 +186,8 @@ type LicenseOptions struct {
// past.
IssuedAt time.Time
Features license.Features
AllowEmpty bool
}
func (opts *LicenseOptions) WithIssuedAt(now time.Time) *LicenseOptions {
@@ -276,10 +278,10 @@ func GenerateLicense(t *testing.T, options LicenseOptions) string {
issuedAt = time.Now().Add(-time.Minute)
}
if options.AccountType == "" {
if !options.AllowEmpty && options.AccountType == "" {
options.AccountType = license.AccountTypeSalesforce
}
if options.AccountID == "" {
if !options.AllowEmpty && options.AccountID == "" {
options.AccountID = "test-account-id"
}
+11 -1
View File
@@ -612,6 +612,8 @@ var (
ErrMissingLicenseExpires = xerrors.New("license has invalid or missing license_expires claim")
ErrMissingExp = xerrors.New("license has invalid or missing exp (expires at) claim")
ErrMultipleIssues = xerrors.New("license has multiple issues; contact support")
ErrMissingAccountType = xerrors.New("license must contain valid account type")
ErrMissingAccountID = xerrors.New("license must contain valid account ID")
)
type Features map[codersdk.FeatureName]int64
@@ -696,12 +698,20 @@ func validateClaims(tok *jwt.Token) (*Claims, error) {
if claims.NotBefore == nil {
return nil, ErrMissingNotBefore
}
if claims.LicenseExpires == nil {
yearsHardLimit := time.Now().Add(5 /* years */ * 365 * 24 * time.Hour)
if claims.LicenseExpires == nil || claims.LicenseExpires.Time.After(yearsHardLimit) {
return nil, ErrMissingLicenseExpires
}
if claims.ExpiresAt == nil {
return nil, ErrMissingExp
}
if claims.AccountType == "" {
return nil, ErrMissingAccountType
}
if claims.AccountID == "" {
return nil, ErrMissingAccountID
}
return claims, nil
}
return nil, xerrors.New("unable to parse Claims")
+50
View File
@@ -54,6 +54,56 @@ func TestPostLicense(t *testing.T) {
require.Contains(t, errResp.Message, "License cannot be used on this deployment!")
})
t.Run("InvalidAccountID", func(t *testing.T) {
t.Parallel()
// The generated deployment will start out with a different deployment ID.
client, _ := coderdenttest.New(t, &coderdenttest.Options{DontAddLicense: true})
license := coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{
AllowEmpty: true,
AccountID: "",
})
_, err := client.AddLicense(context.Background(), codersdk.AddLicenseRequest{
License: license,
})
errResp := &codersdk.Error{}
require.ErrorAs(t, err, &errResp)
require.Equal(t, http.StatusBadRequest, errResp.StatusCode())
require.Contains(t, errResp.Message, "Invalid license")
})
t.Run("InvalidAccountType", func(t *testing.T) {
t.Parallel()
// The generated deployment will start out with a different deployment ID.
client, _ := coderdenttest.New(t, &coderdenttest.Options{DontAddLicense: true})
license := coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{
AllowEmpty: true,
AccountType: "",
})
_, err := client.AddLicense(context.Background(), codersdk.AddLicenseRequest{
License: license,
})
errResp := &codersdk.Error{}
require.ErrorAs(t, err, &errResp)
require.Equal(t, http.StatusBadRequest, errResp.StatusCode())
require.Contains(t, errResp.Message, "Invalid license")
})
t.Run("InvalidLicenseExpires", func(t *testing.T) {
t.Parallel()
// The generated deployment will start out with a different deployment ID.
client, _ := coderdenttest.New(t, &coderdenttest.Options{DontAddLicense: true})
license := coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{
GraceAt: time.Unix(99999999999, 0),
})
_, err := client.AddLicense(context.Background(), codersdk.AddLicenseRequest{
License: license,
})
errResp := &codersdk.Error{}
require.ErrorAs(t, err, &errResp)
require.Equal(t, http.StatusBadRequest, errResp.StatusCode())
require.Contains(t, errResp.Message, "Invalid license")
})
t.Run("Unauthorized", func(t *testing.T) {
t.Parallel()
client, _ := coderdenttest.New(t, &coderdenttest.Options{DontAddLicense: true})