mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-17 20:55:28 +00:00
fix: prevent unnecessary template updates (#6379)
* test(installer): adds `TestIsOutdatedVersionFix` Signed-off-by: Dwi Siswanto <git@dw1.io> * fix: prevent unnecessary template updates when version API fails. * fix `catalog/config.IsOutdatedVersion` logic for empty version strings * add GitHub API fallback when PDTM API is unavail * only show outdated msg for actual version mismatches Signed-off-by: Dwi Siswanto <git@dw1.io> --------- Signed-off-by: Dwi Siswanto <git@dw1.io>
This commit is contained in:
parent
d569cfe864
commit
70eeb6c210
@ -46,18 +46,21 @@ const (
|
|||||||
// if the current version is outdated
|
// if the current version is outdated
|
||||||
func IsOutdatedVersion(current, latest string) bool {
|
func IsOutdatedVersion(current, latest string) bool {
|
||||||
if latest == "" {
|
if latest == "" {
|
||||||
// if pdtm api call failed it's assumed that the current version is outdated
|
// NOTE(dwisiswant0): if PDTM API call failed or returned empty, we
|
||||||
// and it will be confirmed while updating from GitHub
|
// cannot determine if templates are outdated w/o additional checks
|
||||||
// this fixes `version string empty` errors
|
// return false to avoid unnecessary updates.
|
||||||
return true
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
current = trimDevIfExists(current)
|
current = trimDevIfExists(current)
|
||||||
currentVer, _ := semver.NewVersion(current)
|
currentVer, _ := semver.NewVersion(current)
|
||||||
newVer, _ := semver.NewVersion(latest)
|
newVer, _ := semver.NewVersion(latest)
|
||||||
|
|
||||||
if currentVer == nil || newVer == nil {
|
if currentVer == nil || newVer == nil {
|
||||||
// fallback to naive comparison
|
// fallback to naive comparison - return true only if they are different
|
||||||
return current == latest
|
return current != latest
|
||||||
}
|
}
|
||||||
|
|
||||||
return newVer.GreaterThan(currentVer)
|
return newVer.GreaterThan(currentVer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -94,7 +94,24 @@ func (t *TemplateManager) UpdateIfOutdated() error {
|
|||||||
if !fileutil.FolderExists(config.DefaultConfig.TemplatesDirectory) {
|
if !fileutil.FolderExists(config.DefaultConfig.TemplatesDirectory) {
|
||||||
return t.FreshInstallIfNotExists()
|
return t.FreshInstallIfNotExists()
|
||||||
}
|
}
|
||||||
if config.DefaultConfig.NeedsTemplateUpdate() {
|
|
||||||
|
needsUpdate := config.DefaultConfig.NeedsTemplateUpdate()
|
||||||
|
|
||||||
|
// NOTE(dwisiswant0): if PDTM API data is not available
|
||||||
|
// (LatestNucleiTemplatesVersion is empty) but we have a current template
|
||||||
|
// version, so we MUST verify against GitHub directly.
|
||||||
|
if !needsUpdate && config.DefaultConfig.LatestNucleiTemplatesVersion == "" && config.DefaultConfig.TemplateVersion != "" {
|
||||||
|
ghrd, err := updateutils.NewghReleaseDownloader(config.OfficialNucleiTemplatesRepoName)
|
||||||
|
if err == nil {
|
||||||
|
latestVersion := ghrd.Latest.GetTagName()
|
||||||
|
if config.IsOutdatedVersion(config.DefaultConfig.TemplateVersion, latestVersion) {
|
||||||
|
needsUpdate = true
|
||||||
|
gologger.Debug().Msgf("PDTM API unavailable, verified update needed via GitHub API: %s -> %s", config.DefaultConfig.TemplateVersion, latestVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if needsUpdate {
|
||||||
return t.updateTemplatesAt(config.DefaultConfig.TemplatesDirectory)
|
return t.updateTemplatesAt(config.DefaultConfig.TemplatesDirectory)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -142,7 +159,14 @@ func (t *TemplateManager) updateTemplatesAt(dir string) error {
|
|||||||
return errorutil.NewWithErr(err).Msgf("failed to install templates at %s", dir)
|
return errorutil.NewWithErr(err).Msgf("failed to install templates at %s", dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
gologger.Info().Msgf("Your current nuclei-templates %s are outdated. Latest is %s\n", config.DefaultConfig.TemplateVersion, ghrd.Latest.GetTagName())
|
latestVersion := ghrd.Latest.GetTagName()
|
||||||
|
currentVersion := config.DefaultConfig.TemplateVersion
|
||||||
|
|
||||||
|
if config.IsOutdatedVersion(currentVersion, latestVersion) {
|
||||||
|
gologger.Info().Msgf("Your current nuclei-templates %s are outdated. Latest is %s\n", currentVersion, latestVersion)
|
||||||
|
} else {
|
||||||
|
gologger.Debug().Msgf("Updating nuclei-templates from %s to %s (forced update)\n", currentVersion, latestVersion)
|
||||||
|
}
|
||||||
|
|
||||||
// write templates to disk
|
// write templates to disk
|
||||||
if err := t.writeTemplatesToDisk(ghrd, dir); err != nil {
|
if err := t.writeTemplatesToDisk(ghrd, dir); err != nil {
|
||||||
|
|||||||
@ -59,3 +59,42 @@ func TestTemplateInstallation(t *testing.T) {
|
|||||||
require.FileExists(t, config.DefaultConfig.GetIgnoreFilePath())
|
require.FileExists(t, config.DefaultConfig.GetIgnoreFilePath())
|
||||||
t.Logf("Installed %d templates", counter)
|
t.Logf("Installed %d templates", counter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsOutdatedVersion(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
current string
|
||||||
|
latest string
|
||||||
|
expected bool
|
||||||
|
desc string
|
||||||
|
}{
|
||||||
|
// Test the empty latest version case (main bug fix)
|
||||||
|
{"v10.2.7", "", false, "Empty latest version should not trigger update"},
|
||||||
|
|
||||||
|
// Test same versions
|
||||||
|
{"v10.2.7", "v10.2.7", false, "Same versions should not trigger update"},
|
||||||
|
|
||||||
|
// Test outdated version
|
||||||
|
{"v10.2.6", "v10.2.7", true, "Older version should trigger update"},
|
||||||
|
|
||||||
|
// Test newer current version (edge case)
|
||||||
|
{"v10.2.8", "v10.2.7", false, "Newer current version should not trigger update"},
|
||||||
|
|
||||||
|
// Test dev versions
|
||||||
|
{"v10.2.7-dev", "v10.2.7", false, "Dev version matching release should not trigger update"},
|
||||||
|
{"v10.2.6-dev", "v10.2.7", true, "Outdated dev version should trigger update"},
|
||||||
|
|
||||||
|
// Test invalid semver fallback
|
||||||
|
{"invalid-version", "v10.2.7", true, "Invalid current version should trigger update (fallback)"},
|
||||||
|
{"v10.2.7", "invalid-version", true, "Invalid latest version should trigger update (fallback)"},
|
||||||
|
{"same-invalid", "same-invalid", false, "Same invalid versions should not trigger update (fallback)"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
result := config.IsOutdatedVersion(tc.current, tc.latest)
|
||||||
|
require.Equal(t, tc.expected, result,
|
||||||
|
"IsOutdatedVersion(%q, %q) = %t, expected %t",
|
||||||
|
tc.current, tc.latest, result, tc.expected)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user