From d5b480566e1c25e9f3187c99aa94ef48cf867555 Mon Sep 17 00:00:00 2001 From: Krishi Agrawal Date: Sun, 11 Jan 2026 16:37:36 +0530 Subject: [PATCH] fix(licenses): enforce min one obligation requirement Signed-off-by: Krishi Agrawal --- pkg/api/licenses.go | 41 ++++++++++++++++++++++++++++++++++++++++- pkg/models/licenses.go | 5 +++++ pkg/utils/util.go | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/pkg/api/licenses.go b/pkg/api/licenses.go index b5e0a78..378af58 100644 --- a/pkg/api/licenses.go +++ b/pkg/api/licenses.go @@ -252,6 +252,19 @@ func CreateLicense(c *gin.Context) { return } + // Validate that at least one obligation is provided + if input.Obligations == nil || len(*input.Obligations) == 0 { + er := models.LicenseError{ + Status: http.StatusBadRequest, + Message: "can not create license with these field values", + Error: "license must have at least one obligation", + Path: c.Request.URL.Path, + Timestamp: time.Now().Format(time.RFC3339), + } + c.JSON(http.StatusBadRequest, er) + return + } + lic := input.ConvertToLicenseDB() lic.UserId = userId @@ -271,7 +284,7 @@ func CreateLicense(c *gin.Context) { return result.Error } - if err := tx.Preload("User").First(&lic).Error; err != nil { + if err := tx.Preload("User").Preload("Obligations").First(&lic).Error; err != nil { er := models.LicenseError{ Status: http.StatusInternalServerError, Message: "Failed to create license", @@ -283,6 +296,19 @@ func CreateLicense(c *gin.Context) { return result.Error } + // Validate that license has at least one obligation after creation + if len(lic.Obligations) == 0 { + er := models.LicenseError{ + Status: http.StatusBadRequest, + Message: "can not create license with these field values", + Error: "license must have at least one obligation", + Path: c.Request.URL.Path, + Timestamp: time.Now().Format(time.RFC3339), + } + c.JSON(http.StatusBadRequest, er) + return errors.New("license must have at least one obligation") + } + if err := utils.AddChangelogsForLicense(tx, userId, &lic, &models.LicenseDB{}); err != nil { er := models.LicenseError{ Status: http.StatusInternalServerError, @@ -436,6 +462,19 @@ func UpdateLicense(c *gin.Context) { return err } + // Validate that license has at least one obligation after update + if len(newLicense.Obligations) == 0 { + er := models.LicenseError{ + Status: http.StatusBadRequest, + Message: "can not update license with these field values", + Error: "license must have at least one obligation", + Path: c.Request.URL.Path, + Timestamp: time.Now().Format(time.RFC3339), + } + c.JSON(http.StatusBadRequest, er) + return errors.New("license must have at least one obligation") + } + if err := utils.AddChangelogsForLicense(tx, userId, &newLicense, &oldLicense); err != nil { er := models.LicenseError{ Status: http.StatusInternalServerError, diff --git a/pkg/models/licenses.go b/pkg/models/licenses.go index 1cd4bf6..ce030bb 100644 --- a/pkg/models/licenses.go +++ b/pkg/models/licenses.go @@ -262,6 +262,11 @@ func (dto *LicenseImportDTO) ConvertToLicenseDB() LicenseDB { l.ExternalRef = datatypes.NewJSONType(ext) + // Set obligations if provided + if dto.Obligations != nil { + l.Obligations = *dto.Obligations + } + return l } diff --git a/pkg/utils/util.go b/pkg/utils/util.go index f01be78..e186997 100644 --- a/pkg/utils/util.go +++ b/pkg/utils/util.go @@ -126,6 +126,13 @@ func InsertOrUpdateLicenseOnImport(lic *models.LicenseImportDTO, userId uuid.UUI return message, importStatus } + // Validate that at least one obligation is provided for import + if lic.Obligations == nil || len(*lic.Obligations) == 0 { + message = "license must have at least one obligation" + importStatus = IMPORT_FAILED + return message, importStatus + } + _ = db.DB.Transaction(func(tx *gorm.DB) error { license := lic.ConvertToLicenseDB() license.UserId = userId @@ -167,6 +174,20 @@ func InsertOrUpdateLicenseOnImport(lic *models.LicenseImportDTO, userId uuid.UUI lic.Id = &newLicense.Id lic.Shortname = newLicense.Shortname + // Reload license with obligations to check final state + if err := tx.Preload("Obligations").Where(models.LicenseDB{Id: newLicense.Id}).First(&newLicense).Error; err != nil { + message = fmt.Sprintf("failed to update license: %s", err.Error()) + importStatus = IMPORT_FAILED + return errors.New(message) + } + + // Validate that license has at least one obligation after update + if len(newLicense.Obligations) == 0 { + message = "license must have at least one obligation" + importStatus = IMPORT_FAILED + return errors.New(message) + } + if err := AddChangelogsForLicense(tx, userId, &newLicense, &oldLicense); err != nil { message = fmt.Sprintf("failed to update license: %s", err.Error()) importStatus = IMPORT_FAILED @@ -182,6 +203,20 @@ func InsertOrUpdateLicenseOnImport(lic *models.LicenseImportDTO, userId uuid.UUI return errors.New(message) } + // Reload license with obligations to check final state + if err := tx.Preload("Obligations").Where(models.LicenseDB{Id: license.Id}).First(&license).Error; err != nil { + message = fmt.Sprintf("failed to import license: %s", err.Error()) + importStatus = IMPORT_FAILED + return errors.New(message) + } + + // Validate that license has at least one obligation after creation + if len(license.Obligations) == 0 { + message = "license must have at least one obligation" + importStatus = IMPORT_FAILED + return errors.New(message) + } + // for setting api response lic.Id = &license.Id lic.Shortname = license.Shortname