Skip to content

Commit 5145ee9

Browse files
authored
check pdsc files in a pack and correct version compare (#574)
## Fixes - check the position of pdsc files inside a pack for correctness - corrected version compare with list --updatable and existing local pack installations ## Changes - search a pack for existing pdsc files - check version of local installations before those in the index ## Checklist <!-- Put an `x` in the boxes. All tasks must be completed and boxes checked before merging. --> - [ ] 🤖 This change is covered by unit tests (if applicable). - [x] 🤹 Manual testing has been performed (if necessary). - [x] 🛡️ Security impacts have been considered (if relevant). - [x] 📖 Documentation updates are complete (if required). - [x] 🧠 Third-party dependencies and TPIP updated (if required).
1 parent 9daa768 commit 5145ee9

File tree

3 files changed

+105
-59
lines changed

3 files changed

+105
-59
lines changed

cmd/errors/errors.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,18 @@ var (
3232
ErrBadPackVersion = errors.New("bad pack version: cannot add a version with build metadata")
3333

3434
// Errors related to package content
35-
ErrPdscFileNotFound = errors.New("pdsc not found")
36-
ErrPackNotInstalled = errors.New("pack not installed")
37-
ErrPdscEntryExists = errors.New("pdsc already in index")
38-
ErrPdscEntryNotFound = errors.New("pdsc not found in index")
39-
ErrEula = errors.New("user does not agree with the pack's license")
40-
ErrExtractEula = errors.New("user wants to extract embedded license only")
41-
ErrLicenseNotFound = errors.New("embedded license not found")
42-
ErrPackRootNotFound = errors.New("no CMSIS Pack Root directory specified. Either the environment CMSIS_PACK_ROOT needs to be set or the path specified using the command line option -R/--pack-root string")
43-
ErrPackRootDoesNotExist = errors.New("the specified CMSIS Pack Root directory does NOT exist! Please take a moment to review if the value is correct or create a new one via `cpackget init` command")
44-
ErrPdscFileTooDeepInPack = errors.New("pdsc file is too deep in pack file")
35+
ErrPdscFileNotFound = errors.New("pdsc not found")
36+
ErrPackNotInstalled = errors.New("pack not installed")
37+
ErrPdscEntryExists = errors.New("pdsc already in index")
38+
ErrPdscEntryNotFound = errors.New("pdsc not found in index")
39+
ErrEula = errors.New("user does not agree with the pack's license")
40+
ErrExtractEula = errors.New("user wants to extract embedded license only")
41+
ErrLicenseNotFound = errors.New("embedded license not found")
42+
ErrPackRootNotFound = errors.New("no CMSIS Pack Root directory specified. Either the environment CMSIS_PACK_ROOT needs to be set or the path specified using the command line option -R/--pack-root string")
43+
ErrPackRootDoesNotExist = errors.New("the specified CMSIS Pack Root directory does NOT exist! Please take a moment to review if the value is correct or create a new one via `cpackget init` command")
44+
ErrPdscFileTooDeepInPack = errors.New("pdsc file is too deep in pack file")
45+
ErrMultiplePdscFilesInPack = errors.New("multiple pdsc files found in pack file, cannot determine which one to use. Please remove the extra pdsc files")
46+
ErrPdscWrongName = errors.New("pdsc file has wrong name, it should be <PackID>.pdsc")
4547

4648
// Errors related to network
4749
ErrBadRequest = errors.New("bad request")

cmd/installer/pack.go

Lines changed: 80 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -212,78 +212,110 @@ func (p *PackType) fetch(timeout int) error {
212212
// to be installed.
213213
func (p *PackType) validate() error {
214214
log.Debug("Validating pack")
215+
var err error
215216
myPdscFileName := p.PdscFileName()
217+
var validPdscFiles []*zip.File
218+
219+
// Single pass: validate all files and collect valid PDSC files
216220
for _, file := range p.zipReader.File {
217221
ext := strings.ToLower(filepath.Ext(file.Name))
222+
223+
// Ensure all file paths do not contain ".."
224+
if strings.Contains(file.Name, "..") {
225+
if ext == PdscExtension {
226+
log.Errorf("File %q invalid file path", file.Name)
227+
return errs.ErrInvalidFilePath
228+
} else {
229+
return errs.ErrInsecureZipFileName
230+
}
231+
}
232+
218233
if ext == PdscExtension {
219234
// Check if pack was compressed in a subfolder
220235
subfoldersCount := strings.Count(file.Name, "/") + strings.Count(file.Name, "\\")
221236
if subfoldersCount > 1 {
222-
return errs.ErrPdscFileTooDeepInPack
223-
} else if subfoldersCount == 1 {
224-
p.Subfolder = filepath.Dir(file.Name)
225-
}
237+
err = errs.ErrPdscFileTooDeepInPack // save for later decision if error or warning
238+
} else {
239+
tmpFileName := filepath.Base(file.Name) // normalize file name
240+
if !strings.EqualFold(tmpFileName, myPdscFileName) {
241+
if err != nil {
242+
log.Warnf("Pack %q contains an additional .pdsc file in a deeper subfolder, this may cause issues", p.path)
243+
}
244+
return fmt.Errorf("%q: %w", file.Name, errs.ErrPdscWrongName)
245+
}
246+
// Collect valid PDSC files for processing
247+
validPdscFiles = append(validPdscFiles, file)
226248

227-
// Ensure the file path does not contain ".."
228-
if strings.Contains(file.Name, "..") {
229-
log.Errorf("File %q invalid file path", file.Name)
230-
return errs.ErrInvalidFilePath
249+
if subfoldersCount == 1 {
250+
p.Subfolder = filepath.Dir(file.Name)
251+
}
231252
}
253+
}
254+
}
232255

233-
myPdscFileName = p.PackID() + filepath.Ext(file.Name)
256+
if len(validPdscFiles) > 1 {
257+
return errs.ErrMultiplePdscFilesInPack
258+
}
234259

235-
// Read pack's pdsc
236-
tmpPdscFileName := filepath.Join(os.TempDir(), utils.RandStringBytes(10))
237-
defer os.RemoveAll(tmpPdscFileName)
260+
if err != nil {
261+
if len(validPdscFiles) > 0 {
262+
log.Warnf("Pack %q contains an additional .pdsc file in a deeper subfolder, this may cause issues", p.path)
263+
} else {
264+
return err
265+
}
266+
}
238267

239-
if err := utils.SecureInflateFile(file, tmpPdscFileName, ""); err != nil {
240-
return err
241-
}
268+
if len(validPdscFiles) == 0 {
269+
log.Errorf("%q not found in %q", myPdscFileName, p.path)
270+
return errs.ErrPdscFileNotFound
271+
}
242272

243-
p.Pdsc = xml.NewPdscXML(filepath.Join(tmpPdscFileName, file.Name)) // #nosec
244-
if err := p.Pdsc.Read(); err != nil {
245-
return err
246-
}
273+
// Process the first valid PDSC file found
274+
file := validPdscFiles[0]
247275

248-
// Sanity check: make sure the version being installed actually exists in the PDSC file
249-
version := p.GetVersion()
250-
latestVersion := p.Pdsc.LatestVersion()
276+
// Read pack's pdsc
277+
tmpPdscFileName := filepath.Join(os.TempDir(), utils.RandStringBytes(10))
278+
defer os.RemoveAll(tmpPdscFileName)
251279

252-
log.Debugf("Making sure %s is the latest release in %s", version, myPdscFileName)
280+
if err := utils.SecureInflateFile(file, tmpPdscFileName, ""); err != nil {
281+
return err
282+
}
253283

254-
if utils.SemverCompare(version, latestVersion) != 0 {
255-
releaseTag := p.Pdsc.FindReleaseTagByVersion(version)
256-
if releaseTag == nil {
257-
log.Errorf("The pack's pdsc (%s) has no release tag matching version %q", myPdscFileName, version)
258-
return errs.ErrPackVersionNotFoundInPdsc
259-
}
284+
p.Pdsc = xml.NewPdscXML(filepath.Join(tmpPdscFileName, file.Name)) // #nosec
285+
if err := p.Pdsc.Read(); err != nil {
286+
return err
287+
}
260288

261-
log.Errorf("The latest release (%s) in pack's pdsc (%s) does not match pack version %q", latestVersion, myPdscFileName, version)
262-
return errs.ErrPackVersionNotLatestReleasePdsc
263-
}
289+
// Sanity check: make sure the version being installed actually exists in the PDSC file
290+
version := p.GetVersion()
291+
latestVersion := p.Pdsc.LatestVersion()
264292

265-
p.Pdsc.FileName = file.Name
293+
log.Debugf("Making sure %s is the latest release in %s", version, myPdscFileName)
266294

267-
pdscFileName := p.PdscFileName() // destination file name in .Download directory
268-
pdscFilePath := filepath.Join(tmpPdscFileName, file.Name) // #nosec
269-
newPdscFileName := p.PdscFileNameWithVersion()
295+
if utils.SemverCompare(version, latestVersion) != 0 {
296+
releaseTag := p.Pdsc.FindReleaseTagByVersion(version)
297+
if releaseTag == nil {
298+
log.Errorf("The pack's pdsc (%s) has no release tag matching version %q", myPdscFileName, version)
299+
return errs.ErrPackVersionNotFoundInPdsc
300+
}
270301

271-
if !p.IsPublic {
272-
_ = utils.CopyFile(pdscFilePath, filepath.Join(Installation.LocalDir, pdscFileName))
273-
}
302+
log.Errorf("The latest release (%s) in pack's pdsc (%s) does not match pack version %q", latestVersion, myPdscFileName, version)
303+
return errs.ErrPackVersionNotLatestReleasePdsc
304+
}
274305

275-
_ = utils.CopyFile(pdscFilePath, filepath.Join(Installation.DownloadDir, newPdscFileName))
306+
p.Pdsc.FileName = file.Name
276307

277-
return nil
278-
} else {
279-
if strings.Contains(file.Name, "..") {
280-
return errs.ErrInsecureZipFileName
281-
}
282-
}
308+
pdscFileName := p.PdscFileName() // destination file name in .Download directory
309+
pdscFilePath := filepath.Join(tmpPdscFileName, file.Name) // #nosec
310+
newPdscFileName := p.PdscFileNameWithVersion()
311+
312+
if !p.IsPublic {
313+
_ = utils.CopyFile(pdscFilePath, filepath.Join(Installation.LocalDir, pdscFileName))
283314
}
284315

285-
log.Errorf("%q not found in %q", myPdscFileName, p.path)
286-
return errs.ErrPdscFileNotFound
316+
_ = utils.CopyFile(pdscFilePath, filepath.Join(Installation.DownloadDir, newPdscFileName))
317+
318+
return nil
287319
}
288320

289321
// purge removes all cached files matching the pattern derived from the PackType's

cmd/installer/root.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1894,9 +1894,21 @@ func (p *PacksInstallationType) PackIsInstalled(pack *PackType, noLocal bool) (f
18941894
if latestVersion == "" {
18951895
log.Debugf("Could not find latest version for %q", pack.PackIDWithVersion())
18961896
} else {
1897+
log.Debugf("Checking for installed packs %s", utils.FormatVersions(pack.Version))
1898+
for _, version := range installedVersions {
1899+
log.Debugf("- checking against: %s", version)
1900+
if utils.SemverCompare(version, latestVersion) >= 0 {
1901+
found = true
1902+
return
1903+
}
1904+
}
18971905
packDir := filepath.Join(installationDir, latestVersion)
18981906
found = utils.DirExists(packDir)
1899-
pack.targetVersion = latestVersion
1907+
if !found && utils.SemverCompare(latestVersion, pack.Version) >= 0 {
1908+
pack.targetVersion = latestVersion
1909+
} else {
1910+
pack.targetVersion = pack.Version
1911+
}
19001912
}
19011913
}
19021914

0 commit comments

Comments
 (0)