chore: Force license uuids to not be null (#6012)

* chore: Force license uuids to not be null

* All unit tests generate uuids for licenses

* Update migration files to new numbers

* Put migration in transaction
This commit is contained in:
Steven Masley 2023-02-13 18:21:58 -06:00 committed by GitHub
parent a54de6093b
commit 733f58c76d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 39 additions and 25 deletions

View File

@ -211,7 +211,7 @@ CREATE TABLE licenses (
uploaded_at timestamp with time zone NOT NULL,
jwt text NOT NULL,
exp timestamp with time zone NOT NULL,
uuid uuid
uuid uuid NOT NULL
);
COMMENT ON COLUMN licenses.exp IS 'exp tracks the claim of the same name in the JWT, and we include it here so that we can easily query for licenses that have not yet expired.';

View File

@ -0,0 +1 @@
ALTER TABLE ONLY licenses ALTER COLUMN uuid DROP NOT NULL;

View File

@ -0,0 +1,8 @@
BEGIN;
-- We need to assign uuids to any existing licenses that don't have them.
UPDATE licenses SET uuid = gen_random_uuid() WHERE uuid IS NULL;
-- Assert no licenses have null uuids.
ALTER TABLE ONLY licenses ALTER COLUMN uuid SET NOT NULL;
COMMIT;

View File

@ -1288,8 +1288,8 @@ type License struct {
UploadedAt time.Time `db:"uploaded_at" json:"uploaded_at"`
JWT string `db:"jwt" json:"jwt"`
// exp tracks the claim of the same name in the JWT, and we include it here so that we can easily query for licenses that have not yet expired.
Exp time.Time `db:"exp" json:"exp"`
Uuid uuid.NullUUID `db:"uuid" json:"uuid"`
Exp time.Time `db:"exp" json:"exp"`
UUID uuid.UUID `db:"uuid" json:"uuid"`
}
type Organization struct {

View File

@ -1363,7 +1363,7 @@ func (q *sqlQuerier) GetLicenses(ctx context.Context) ([]License, error) {
&i.UploadedAt,
&i.JWT,
&i.Exp,
&i.Uuid,
&i.UUID,
); err != nil {
return nil, err
}
@ -1399,7 +1399,7 @@ func (q *sqlQuerier) GetUnexpiredLicenses(ctx context.Context) ([]License, error
&i.UploadedAt,
&i.JWT,
&i.Exp,
&i.Uuid,
&i.UUID,
); err != nil {
return nil, err
}
@ -1427,10 +1427,10 @@ VALUES
`
type InsertLicenseParams struct {
UploadedAt time.Time `db:"uploaded_at" json:"uploaded_at"`
JWT string `db:"jwt" json:"jwt"`
Exp time.Time `db:"exp" json:"exp"`
Uuid uuid.NullUUID `db:"uuid" json:"uuid"`
UploadedAt time.Time `db:"uploaded_at" json:"uploaded_at"`
JWT string `db:"jwt" json:"jwt"`
Exp time.Time `db:"exp" json:"exp"`
UUID uuid.UUID `db:"uuid" json:"uuid"`
}
func (q *sqlQuerier) InsertLicense(ctx context.Context, arg InsertLicenseParams) (License, error) {
@ -1438,7 +1438,7 @@ func (q *sqlQuerier) InsertLicense(ctx context.Context, arg InsertLicenseParams)
arg.UploadedAt,
arg.JWT,
arg.Exp,
arg.Uuid,
arg.UUID,
)
var i License
err := row.Scan(
@ -1446,7 +1446,7 @@ func (q *sqlQuerier) InsertLicense(ctx context.Context, arg InsertLicenseParams)
&i.UploadedAt,
&i.JWT,
&i.Exp,
&i.Uuid,
&i.UUID,
)
return i, err
}

View File

@ -43,6 +43,7 @@ overrides:
troubleshooting_url: TroubleshootingURL
default_ttl: DefaultTTL
motd_file: MOTDFile
uuid: UUID
sql:
- schema: "./dump.sql"

View File

@ -645,7 +645,7 @@ func ConvertTemplateVersion(version database.TemplateVersion) TemplateVersion {
func ConvertLicense(license database.License) License {
return License{
UploadedAt: license.UploadedAt,
UUID: license.Uuid.UUID,
UUID: license.UUID,
}
}

View File

@ -71,10 +71,7 @@ func TestTelemetry(t *testing.T) {
UploadedAt: database.Now(),
JWT: "",
Exp: database.Now().Add(time.Hour),
Uuid: uuid.NullUUID{
UUID: uuid.New(),
Valid: true,
},
UUID: uuid.New(),
})
assert.NoError(t, err)
_, snapshot := collectSnapshot(t, db)

View File

@ -11,6 +11,7 @@ import (
"time"
"github.com/golang-jwt/jwt/v4"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -128,6 +129,7 @@ func GenerateLicense(t *testing.T, options LicenseOptions) string {
c := &license.Claims{
RegisteredClaims: jwt.RegisteredClaims{
ID: uuid.NewString(),
Issuer: "test@testing.test",
ExpiresAt: jwt.NewNumericDate(options.ExpiresAt),
NotBefore: jwt.NewNumericDate(time.Now().Add(-time.Minute)),

View File

@ -98,14 +98,19 @@ func (api *API) postLicense(rw http.ResponseWriter, r *http.Request) {
}
id, err := uuid.Parse(claims.ID)
if err != nil {
// If no uuid is in the license, we generate a random uuid.
// This is not ideal, and this should be fixed to require a uuid
// for all licenses. We require this patch to support older licenses.
// TODO: In the future (April 2023?) we should remove this and reissue
// old licenses with a uuid.
id = uuid.New()
}
dl, err := api.Database.InsertLicense(ctx, database.InsertLicenseParams{
UploadedAt: database.Now(),
JWT: addLicense.License,
Exp: expTime,
Uuid: uuid.NullUUID{
UUID: id,
Valid: err == nil,
},
UUID: id,
})
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
@ -229,7 +234,7 @@ func (api *API) deleteLicense(rw http.ResponseWriter, r *http.Request) {
func convertLicense(dl database.License, c jwt.MapClaims) codersdk.License {
return codersdk.License{
ID: dl.ID,
UUID: dl.Uuid.UUID,
UUID: dl.UUID,
UploadedAt: dl.UploadedAt,
Claims: c,
}

View File

@ -64,14 +64,14 @@ func New(db database.Store, url string, keys map[string]ed25519.PublicKey) func(
return xerrors.Errorf("parse claims: %w", err)
}
id, err := uuid.Parse(claims.ID)
if err != nil {
return xerrors.Errorf("parse uuid: %w", err)
}
_, err = db.InsertLicense(ctx, database.InsertLicenseParams{
UploadedAt: database.Now(),
JWT: string(raw),
Exp: expTime,
Uuid: uuid.NullUUID{
UUID: id,
Valid: err == nil,
},
UUID: id,
})
if err != nil {
return xerrors.Errorf("insert license: %w", err)