diff --git a/internal/rule/ruleconfiguration/ruleconfiguration.go b/internal/rule/ruleconfiguration/ruleconfiguration.go
index 70f91237..6ac12db3 100644
--- a/internal/rule/ruleconfiguration/ruleconfiguration.go
+++ b/internal/rule/ruleconfiguration/ruleconfiguration.go
@@ -4217,12 +4217,316 @@ var configurations = []Type{
 		ErrorModes:       []rulemode.Type{rulemode.Strict},
 		RuleFunction:     rulefunction.PackageIndexPackagesPlatformsToolsDependenciesVersionNonSemver,
 	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "package",
+		ID:               "IT001",
+		Brief:            "packages[].tools[] missing",
+		Description:      "",
+		MessageTemplate:  "Missing packages[].tools property in package(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsMissing,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT002",
+		Brief:            "incorrect packages[].tools type",
+		Description:      "Must be an array.",
+		MessageTemplate:  "packages[].tools property has incorrect type in package(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsIncorrectType,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT003",
+		Brief:            "additional properties in packages[].tools[]",
+		Description:      "",
+		MessageTemplate:  "Unknown properties under packages[].tools[] found in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsAdditionalProperties,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT004",
+		Brief:            "packages[].tools[].name missing",
+		Description:      "",
+		MessageTemplate:  "Missing packages[].tools[].name property in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsNameMissing,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT005",
+		Brief:            "incorrect packages[].tools[].name type",
+		Description:      "Must be a string.",
+		MessageTemplate:  "packages[].tools[].name property has incorrect type in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsNameIncorrectType,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT006",
+		Brief:            "packages[].tools[].name < min length",
+		Description:      "",
+		MessageTemplate:  "packages[].tools[].name value less than the minimum length in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsNameLTMinLength,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT007",
+		Brief:            "packages[].tools[].version missing",
+		Description:      "",
+		MessageTemplate:  "Missing packages[].tools[].version property in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsVersionMissing,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT008",
+		Brief:            "incorrect packages[].tools[].version type",
+		Description:      "Must be a string.",
+		MessageTemplate:  "packages[].tools[].version property has incorrect type in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsVersionIncorrectType,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT009",
+		Brief:            "invalid packages[].tools[].version",
+		Description:      "Must be compliant with \"relaxed semver\".",
+		MessageTemplate:  "Invalid packages[].tools[].version property in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsVersionNonRelaxedSemver,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT010",
+		Brief:            "non-semver packages[].tools[].version",
+		Description:      "",
+		MessageTemplate:  "packages[].tools[].version property in tool(s): {{.}} is not compliant with the semver specification. See: https://semver.org/",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     []rulemode.Type{rulemode.Default},
+		ErrorModes:       []rulemode.Type{rulemode.Strict},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsVersionNonSemver,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT011",
+		Brief:            "packages[].tools[].systems[] missing",
+		Description:      "",
+		MessageTemplate:  "Missing packages[].tools[].systems[] property in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsMissing,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT012",
+		Brief:            "incorrect packages[].tools[].systems type",
+		Description:      "Must be an array.",
+		MessageTemplate:  "packages[].tools[].systems property has incorrect type in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsIncorrectType,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT013",
+		Brief:            "additional properties in packages[].tools[].systems[]",
+		Description:      "",
+		MessageTemplate:  "Unknown properties under packages[].tools[].systems[] found in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsAdditionalProperties,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT014",
+		Brief:            "packages[].tools[].systems[].host missing",
+		Description:      "",
+		MessageTemplate:  "Missing packages[].tools[].systems[].host property in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsHostMissing,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT015",
+		Brief:            "incorrect packages[].tools[].systems[].host type",
+		Description:      "Must be a string.",
+		MessageTemplate:  "packages[].tools[].systems[].host property has incorrect type in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsHostIncorrectType,
+	},
 	{
 		ProjectType:      projecttype.PackageIndex,
 		SuperprojectType: projecttype.All,
 		Category:         "data",
 		Subcategory:      "tool",
-		ID:               "ID007",
+		ID:               "IT0016",
+		Brief:            "invalid packages[].tools[].systems[].host",
+		Description:      "",
+		MessageTemplate:  "packages[].tools[].systems[].host has an invalid format in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsHostInvalid,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT017",
+		Brief:            "packages[].tools[].systems[].url missing",
+		Description:      "",
+		MessageTemplate:  "Missing packages[].tools[].systems[].url property in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsUrlMissing,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT018",
+		Brief:            "incorrect packages[].tools[].systems[].url type",
+		Description:      "Must be a string.",
+		MessageTemplate:  "packages[].tools[].systems[].url property has incorrect type in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsUrlIncorrectType,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT019",
+		Brief:            "invalid packages[].tools[].systems[].url format",
+		Description:      "",
+		MessageTemplate:  "packages[].tools[].systems[].url property does not have a valid URL format in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsUrlInvalidFormat,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT020",
 		Brief:            "dead packages[].tools[].systems[].url",
 		Description:      "",
 		MessageTemplate:  "Unable to load the packages[].tools[].systems[].url URL for tools(s): {{.}}",
@@ -4233,4 +4537,180 @@ var configurations = []Type{
 		ErrorModes:       []rulemode.Type{rulemode.Default},
 		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsURLDeadLink,
 	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT021",
+		Brief:            "packages[].tools[].systems[].archiveFileName missing",
+		Description:      "",
+		MessageTemplate:  "Missing packages[].tools[].systems[].archiveFileName property in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsArchiveFileNameMissing,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT022",
+		Brief:            "incorrect packages[].tools[].systems[].archiveFileName type",
+		Description:      "Must be a string.",
+		MessageTemplate:  "packages[].tools[].systems[].archiveFileName property has incorrect type in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsArchiveFileNameIncorrectType,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT023",
+		Brief:            "packages[].tools[].systems[].archiveFileName < min length",
+		Description:      "",
+		MessageTemplate:  "packages[].tools[].systems[].archiveFileName value less than the minimum length in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsArchiveFileNameLTMinLength,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT0024",
+		Brief:            "invalid packages[].tools[].systems[].archiveFileName",
+		Description:      "",
+		MessageTemplate:  "packages[].tools[].systems[].archiveFileName has an invalid format in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsArchiveFileNameInvalid,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT025 ",
+		Brief:            "packages[].tools[].systems[].checksum missing",
+		Description:      "",
+		MessageTemplate:  "Missing packages[].tools[].systems[].checksum property in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsChecksumMissing,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT026",
+		Brief:            "incorrect packages[].tools[].systems[].checksum type",
+		Description:      "Must be a string.",
+		MessageTemplate:  "packages[].tools[].systems[].checksum property has incorrect type in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsChecksumIncorrectType,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT027",
+		Brief:            "invalid packages[].tools[].systems[].checksum",
+		Description:      "",
+		MessageTemplate:  "packages[].tools[].systems[].checksum has an invalid format in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsChecksumInvalid,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT028",
+		Brief:            "discouraged packages[].tools[].systems[].checksum algorithm",
+		Description:      "",
+		MessageTemplate:  "packages[].tools[].systems[].checksum uses a discouraged hash algorithm in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     []rulemode.Type{rulemode.Default},
+		ErrorModes:       []rulemode.Type{rulemode.Strict},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsChecksumDiscouragedAlgorithm,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT029",
+		Brief:            "packages[].tools[].systems[].size missing",
+		Description:      "",
+		MessageTemplate:  "Missing packages[].tools[].systems[].size property in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsSizeMissing,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT030",
+		Brief:            "incorrect packages[].tools[].systems[].size type",
+		Description:      "Must be a string.",
+		MessageTemplate:  "packages[].tools[].systems[].size property has incorrect type in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsSizeIncorrectType,
+	},
+	{
+		ProjectType:      projecttype.PackageIndex,
+		SuperprojectType: projecttype.All,
+		Category:         "data",
+		Subcategory:      "tool",
+		ID:               "IT031",
+		Brief:            "invalid packages[].tools[].systems[].size",
+		Description:      "",
+		MessageTemplate:  "packages[].tools[].systems[].size has an invalid format in tool(s): {{.}}",
+		DisableModes:     nil,
+		EnableModes:      []rulemode.Type{rulemode.Default},
+		InfoModes:        nil,
+		WarningModes:     nil,
+		ErrorModes:       []rulemode.Type{rulemode.Default},
+		RuleFunction:     rulefunction.PackageIndexPackagesToolsSystemsSizeInvalid,
+	},
 }
diff --git a/internal/rule/rulefunction/packageindex.go b/internal/rule/rulefunction/packageindex.go
index dbda0e38..05557896 100644
--- a/internal/rule/rulefunction/packageindex.go
+++ b/internal/rule/rulefunction/packageindex.go
@@ -1755,6 +1755,386 @@ func PackageIndexPackagesPlatformsToolsDependenciesVersionNonSemver() (result ru
 	return ruleresult.Pass, ""
 }
 
+// PackageIndexPackagesToolsMissing checks for missing packages[].tools property.
+func PackageIndexPackagesToolsMissing() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, packageData := range projectdata.PackageIndexPackages() {
+		if schema.RequiredPropertyMissing(packageData.JSONPointer+"/tools", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, packageData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsIncorrectType checks for incorrect type of packages[].tools.
+func PackageIndexPackagesToolsIncorrectType() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, packageData := range projectdata.PackageIndexPackages() {
+		if schema.PropertyTypeMismatch(packageData.JSONPointer+"/tools", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, packageData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsAdditionalProperties checks for additional properties in packages[].tools[].
+func PackageIndexPackagesToolsAdditionalProperties() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, toolData := range projectdata.PackageIndexTools() {
+		if schema.ProhibitedAdditionalProperties(toolData.JSONPointer, projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, toolData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsNameMissing checks for missing packages[].tools[].name property.
+func PackageIndexPackagesToolsNameMissing() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, toolData := range projectdata.PackageIndexTools() {
+		if schema.RequiredPropertyMissing(toolData.JSONPointer+"/name", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, toolData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsNameIncorrectType checks for incorrect type of the packages[].tools[].name property.
+func PackageIndexPackagesToolsNameIncorrectType() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, toolData := range projectdata.PackageIndexTools() {
+		if schema.PropertyTypeMismatch(toolData.JSONPointer+"/name", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, toolData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsNameLTMinLength checks for packages[].tools[].name property less than the minimum length.
+func PackageIndexPackagesToolsNameLTMinLength() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, toolData := range projectdata.PackageIndexTools() {
+		if schema.PropertyLessThanMinLength(toolData.JSONPointer+"/name", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, toolData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsVersionMissing checks for missing packages[].tools[].version property.
+func PackageIndexPackagesToolsVersionMissing() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, toolData := range projectdata.PackageIndexTools() {
+		if schema.RequiredPropertyMissing(toolData.JSONPointer+"/version", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, toolData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsVersionIncorrectType checks for incorrect type of the packages[].tools[].version property.
+func PackageIndexPackagesToolsVersionIncorrectType() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, toolData := range projectdata.PackageIndexTools() {
+		if schema.PropertyTypeMismatch(toolData.JSONPointer+"/version", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, toolData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsVersionNonRelaxedSemver checks whether the packages[].tools[].version property is "relaxed semver" compliant.
+func PackageIndexPackagesToolsVersionNonRelaxedSemver() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, toolData := range projectdata.PackageIndexTools() {
+		if schema.PropertyPatternMismatch(toolData.JSONPointer+"/version", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, toolData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsVersionNonSemver checks whether the packages[].tools[].version property is semver compliant.
+func PackageIndexPackagesToolsVersionNonSemver() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, toolData := range projectdata.PackageIndexTools() {
+		if schema.PropertyPatternMismatch(toolData.JSONPointer+"/version", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Strict]) {
+			nonCompliantIDs = append(nonCompliantIDs, toolData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsMissing checks for missing packages[].tools[].systems[] property.
+func PackageIndexPackagesToolsSystemsMissing() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, toolData := range projectdata.PackageIndexTools() {
+		if schema.RequiredPropertyMissing(toolData.JSONPointer+"/systems", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, toolData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsIncorrectType checks for incorrect type of the packages[].tools[].systems property.
+func PackageIndexPackagesToolsSystemsIncorrectType() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, toolData := range projectdata.PackageIndexTools() {
+		if schema.PropertyTypeMismatch(toolData.JSONPointer+"/systems", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, toolData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsAdditionalProperties checks for additional properties in packages[].tools[].systems[].
+func PackageIndexPackagesToolsSystemsAdditionalProperties() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.ProhibitedAdditionalProperties(systemData.JSONPointer, projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsHostMissing checks for missing packages[].tools[].systems[].host property.
+func PackageIndexPackagesToolsSystemsHostMissing() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.RequiredPropertyMissing(systemData.JSONPointer+"/host", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsHostIncorrectType checks for incorrect type of the packages[].tools[].systems[].host property.
+func PackageIndexPackagesToolsSystemsHostIncorrectType() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.PropertyTypeMismatch(systemData.JSONPointer+"/host", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsHostInvalid checks for invalid format of whether the packages[].tools[].systems[].host property.
+func PackageIndexPackagesToolsSystemsHostInvalid() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.PropertyPatternMismatch(systemData.JSONPointer+"/host", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsUrlMissing checks for missing packages[].tools[].systems[].url property.
+func PackageIndexPackagesToolsSystemsUrlMissing() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.RequiredPropertyMissing(systemData.JSONPointer+"/url", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsUrlIncorrectType checks for incorrect type of the packages[].tools[].systems[].url property.
+func PackageIndexPackagesToolsSystemsUrlIncorrectType() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.PropertyTypeMismatch(systemData.JSONPointer+"/url", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsUrlInvalidFormat checks for incorrect format of the packages[].tools[].systems[].url property.
+func PackageIndexPackagesToolsSystemsUrlInvalidFormat() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.PropertyFormatMismatch(systemData.JSONPointer+"/url", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
 // PackageIndexPackagesToolsSystemsURLDeadLink checks for dead links in packages[].tools[].systems[].url.
 func PackageIndexPackagesToolsSystemsURLDeadLink() (result ruleresult.Type, output string) {
 	if projectdata.PackageIndexLoadError() != nil {
@@ -1785,3 +2165,223 @@ func PackageIndexPackagesToolsSystemsURLDeadLink() (result ruleresult.Type, outp
 
 	return ruleresult.Pass, ""
 }
+
+// PackageIndexPackagesToolsSystemsArchiveFileNameMissing checks for missing packages[].tools[].systems[].archiveFileName property.
+func PackageIndexPackagesToolsSystemsArchiveFileNameMissing() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.RequiredPropertyMissing(systemData.JSONPointer+"/archiveFileName", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsArchiveFileNameIncorrectType checks for incorrect type of the packages[].tools[].systems[].archiveFileName property.
+func PackageIndexPackagesToolsSystemsArchiveFileNameIncorrectType() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.PropertyTypeMismatch(systemData.JSONPointer+"/archiveFileName", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsArchiveFileNameLTMinLength checks for packages[].tools[].systems[].archiveFileName property less than the minimum length.
+func PackageIndexPackagesToolsSystemsArchiveFileNameLTMinLength() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.PropertyLessThanMinLength(systemData.JSONPointer+"/archiveFileName", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsArchiveFileNameInvalid checks for invalid format of packages[].tools[].systems[].archiveFileName property.
+func PackageIndexPackagesToolsSystemsArchiveFileNameInvalid() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.PropertyPatternMismatch(systemData.JSONPointer+"/archiveFileName", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsChecksumMissing checks for missing packages[].tools[].systems[].checksum property.
+func PackageIndexPackagesToolsSystemsChecksumMissing() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.RequiredPropertyMissing(systemData.JSONPointer+"/checksum", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsChecksumIncorrectType checks for incorrect type of the packages[].tools[].systems[].checksum property.
+func PackageIndexPackagesToolsSystemsChecksumIncorrectType() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.PropertyTypeMismatch(systemData.JSONPointer+"/checksum", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsChecksumInvalid checks for invalid format of packages[].tools[].systems[].checksum property.
+func PackageIndexPackagesToolsSystemsChecksumInvalid() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.PropertyPatternMismatch(systemData.JSONPointer+"/checksum", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsChecksumDiscouragedAlgorithm checks for use of discouraged hash algorithm in packages[].tools[].systems[].checksum property.
+func PackageIndexPackagesToolsSystemsChecksumDiscouragedAlgorithm() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.ValidationErrorMatch("^#"+systemData.JSONPointer+"/checksum$", "/patternObjects/usesSHA256", "", "", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Strict]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsSizeMissing checks for missing packages[].tools[].systems[].size property.
+func PackageIndexPackagesToolsSystemsSizeMissing() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.RequiredPropertyMissing(systemData.JSONPointer+"/size", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsSizeIncorrectType checks for incorrect type of the packages[].tools[].systems[].size property.
+func PackageIndexPackagesToolsSystemsSizeIncorrectType() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.PropertyTypeMismatch(systemData.JSONPointer+"/size", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
+
+// PackageIndexPackagesToolsSystemsSizeInvalid checks for invalid format of packages[].tools[].systems[].size property.
+func PackageIndexPackagesToolsSystemsSizeInvalid() (result ruleresult.Type, output string) {
+	if projectdata.PackageIndexLoadError() != nil {
+		return ruleresult.NotRun, "Error loading package index"
+	}
+
+	nonCompliantIDs := []string{}
+	for _, systemData := range projectdata.PackageIndexSystems() {
+		if schema.PropertyPatternMismatch(systemData.JSONPointer+"/size", projectdata.PackageIndexSchemaValidationResult()[compliancelevel.Specification]) {
+			nonCompliantIDs = append(nonCompliantIDs, systemData.ID)
+		}
+	}
+
+	if len(nonCompliantIDs) > 0 {
+		return ruleresult.Fail, strings.Join(nonCompliantIDs, ", ")
+	}
+
+	return ruleresult.Pass, ""
+}
diff --git a/internal/rule/rulefunction/packageindex_test.go b/internal/rule/rulefunction/packageindex_test.go
index 29d231d9..9af599c4 100644
--- a/internal/rule/rulefunction/packageindex_test.go
+++ b/internal/rule/rulefunction/packageindex_test.go
@@ -922,6 +922,196 @@ func TestPackageIndexPackagesPlatformsToolsDependenciesVersionNonSemver(t *testi
 	checkPackageIndexRuleFunction(PackageIndexPackagesPlatformsToolsDependenciesVersionNonSemver, testTables, t)
 }
 
+func TestPackageIndexPackagesToolsMissing(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools missing", "packages-tools-missing", ruleresult.Fail, "^foopackager$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsMissing, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsIncorrectType(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Incorrect packages[].tools type", "packages-tools-incorrect-type", ruleresult.Fail, "^foopackager$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsIncorrectType, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsAdditionalProperties(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Additional packages[].tools[] properties", "packages-tools-additional-properties", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsAdditionalProperties, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsNameMissing(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools[].name missing", "packages-tools-name-missing", ruleresult.Fail, "^/packages/0/tools/0$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsNameMissing, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsNameIncorrectType(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Incorrect packages[].tools.name type", "packages-tools-name-incorrect-type", ruleresult.Fail, "^/packages/0/tools/0$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsNameIncorrectType, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsNameLTMinLength(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools[].name < min length", "packages-tools-name-length-lt", ruleresult.Fail, "^/packages/0/tools/0$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsNameLTMinLength, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsVersionMissing(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools[].version missing", "packages-tools-version-missing", ruleresult.Fail, "^/packages/0/tools/0$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsVersionMissing, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsVersionIncorrectType(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Incorrect packages[].tools[].version type", "packages-tools-version-incorrect-type", ruleresult.Fail, "^/packages/0/tools/0$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsVersionIncorrectType, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsVersionNonRelaxedSemver(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools[].version not relaxed semver", "packages-tools-version-non-relaxed-semver", ruleresult.Fail, "^foopackager:openocd@foo$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsVersionNonRelaxedSemver, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsVersionNonSemver(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools[].version not semver", "packages-tools-version-not-semver", ruleresult.Fail, "^foopackager:openocd@1.0$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsVersionNonSemver, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsMissing(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools[].systems[] missing", "packages-tools-systems-missing", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsMissing, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsIncorrectType(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Incorrect packages[].tools[].systems type", "packages-tools-systems-incorrect-type", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsIncorrectType, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsAdditionalProperties(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Additional packages[].tools[].systems[] properties", "packages-tools-systems-additional-properties", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsAdditionalProperties, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsHostMissing(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools[].systems[].host missing", "packages-tools-systems-host-missing", ruleresult.Fail, "^/packages/0/tools/0/systems/0$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsHostMissing, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsHostIncorrectType(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Incorrect packages[].tools[].systems[].host type", "packages-tools-systems-host-incorrect-type", ruleresult.Fail, "^/packages/0/tools/0/systems/0$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsHostIncorrectType, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsHostInvalid(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Invalid packages[].tools[].systems[].host format", "packages-tools-systems-host-invalid", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - foo$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsHostInvalid, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsUrlMissing(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools[].systems[].url missing", "packages-tools-systems-url-missing", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsUrlMissing, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsUrlIncorrectType(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Incorrect packages[].tools[].systems[].url type", "packages-tools-systems-url-incorrect-type", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsUrlIncorrectType, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsUrlInvalidFormat(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Incorrect packages[].tools[].systems[].url format", "packages-tools-systems-url-invalid-format", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsUrlInvalidFormat, testTables, t)
+}
+
 func TestPackageIndexPackagesToolsSystemsURLDeadLink(t *testing.T) {
 	testTables := []packageIndexRuleFunctionTestTable{
 		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
@@ -931,3 +1121,113 @@ func TestPackageIndexPackagesToolsSystemsURLDeadLink(t *testing.T) {
 
 	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsURLDeadLink, testTables, t)
 }
+
+func TestPackageIndexPackagesToolsSystemsArchiveFileNameMissing(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools[].systems[].archiveFileName missing", "packages-tools-systems-archivefilename-missing", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsArchiveFileNameMissing, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsArchiveFileNameIncorrectType(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Incorrect packages[].tools[].systems[].archiveFileName type", "packages-tools-systems-archivefilename-incorrect-type", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsArchiveFileNameIncorrectType, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsArchiveFileNameLTMinLength(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools[].systems[].archiveFileName < min length", "packages-tools-systems-archivefilename-length-lt", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsArchiveFileNameLTMinLength, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsArchiveFileNameInvalid(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Invalid packages[].tools[].systems[].archiveFileName format", "packages-tools-systems-archivefilename-invalid", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsArchiveFileNameInvalid, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsChecksumMissing(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools[].systems[].checksum missing", "packages-tools-systems-checksum-missing", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsChecksumMissing, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsChecksumIncorrectType(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Incorrect packages[].tools[].systems[].checksum type", "packages-tools-systems-checksum-incorrect-type", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsChecksumIncorrectType, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsChecksumInvalid(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Invalid packages[].tools[].systems[].checksum format", "packages-tools-systems-checksum-invalid", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsChecksumInvalid, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsChecksumDiscouragedAlgorithm(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools[].systems[].checksum uses discouraged algorithm", "packages-tools-systems-checksum-discouraged", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsChecksumDiscouragedAlgorithm, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsSizeMissing(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"packages[].tools[].systems[].size missing", "packages-tools-systems-size-missing", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsSizeMissing, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsSizeIncorrectType(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Incorrect packages[].tools[].systems[].size type", "packages-tools-systems-size-incorrect-type", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsSizeIncorrectType, testTables, t)
+}
+
+func TestPackageIndexPackagesToolsSystemsSizeInvalid(t *testing.T) {
+	testTables := []packageIndexRuleFunctionTestTable{
+		{"Invalid JSON", "invalid-JSON", ruleresult.NotRun, ""},
+		{"Invalid packages[].tools[].systems[].size format", "packages-tools-systems-size-invalid", ruleresult.Fail, "^foopackager:openocd@0\\.11\\.0-arduino2 - aarch64-linux-gnu$"},
+		{"Valid", "valid-package-index", ruleresult.Pass, ""},
+	}
+
+	checkPackageIndexRuleFunction(PackageIndexPackagesToolsSystemsSizeInvalid, testTables, t)
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-additional-properties/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-additional-properties/package_foo_index.json
new file mode 100644
index 00000000..19d89fb1
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-additional-properties/package_foo_index.json
@@ -0,0 +1,73 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "foo": "bar",
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-incorrect-type/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-incorrect-type/package_foo_index.json
new file mode 100644
index 00000000..ee7c9f2d
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-incorrect-type/package_foo_index.json
@@ -0,0 +1,31 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": "foo"
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-missing/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-missing/package_foo_index.json
new file mode 100644
index 00000000..3da5f51d
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-missing/package_foo_index.json
@@ -0,0 +1,14 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": []
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-name-incorrect-type/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-name-incorrect-type/package_foo_index.json
new file mode 100644
index 00000000..ebfb587e
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-name-incorrect-type/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": 42,
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-name-length-lt/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-name-length-lt/package_foo_index.json
new file mode 100644
index 00000000..f1f88dd1
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-name-length-lt/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-name-missing/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-name-missing/package_foo_index.json
new file mode 100644
index 00000000..09bbafde
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-name-missing/package_foo_index.json
@@ -0,0 +1,71 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-additional-properties/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-additional-properties/package_foo_index.json
new file mode 100644
index 00000000..6ac95e52
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-additional-properties/package_foo_index.json
@@ -0,0 +1,73 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "foo": "bar",
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-archivefilename-incorrect-type/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-archivefilename-incorrect-type/package_foo_index.json
new file mode 100644
index 00000000..ebbbb282
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-archivefilename-incorrect-type/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": 42,
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-archivefilename-invalid/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-archivefilename-invalid/package_foo_index.json
new file mode 100644
index 00000000..c855220d
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-archivefilename-invalid/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "foo",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-archivefilename-length-lt/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-archivefilename-length-lt/package_foo_index.json
new file mode 100644
index 00000000..bc08bc49
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-archivefilename-length-lt/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-archivefilename-missing/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-archivefilename-missing/package_foo_index.json
new file mode 100644
index 00000000..6320d2d1
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-archivefilename-missing/package_foo_index.json
@@ -0,0 +1,71 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-checksum-discouraged/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-checksum-discouraged/package_foo_index.json
new file mode 100644
index 00000000..aeb5fbe9
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-checksum-discouraged/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-checksum-incorrect-type/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-checksum-incorrect-type/package_foo_index.json
new file mode 100644
index 00000000..163ebf9e
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-checksum-incorrect-type/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": 42,
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-checksum-invalid/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-checksum-invalid/package_foo_index.json
new file mode 100644
index 00000000..793903ef
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-checksum-invalid/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "foo",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-checksum-missing/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-checksum-missing/package_foo_index.json
new file mode 100644
index 00000000..99711759
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-checksum-missing/package_foo_index.json
@@ -0,0 +1,71 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-host-incorrect-type/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-host-incorrect-type/package_foo_index.json
new file mode 100644
index 00000000..b2db6444
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-host-incorrect-type/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": 42,
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-host-invalid/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-host-invalid/package_foo_index.json
new file mode 100644
index 00000000..d3a47a72
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-host-invalid/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "foo",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-host-missing/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-host-missing/package_foo_index.json
new file mode 100644
index 00000000..81b64f76
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-host-missing/package_foo_index.json
@@ -0,0 +1,71 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-incorrect-type/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-incorrect-type/package_foo_index.json
new file mode 100644
index 00000000..c821c938
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-incorrect-type/package_foo_index.json
@@ -0,0 +1,57 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": "foo"
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-missing/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-missing/package_foo_index.json
new file mode 100644
index 00000000..3c60d2cf
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-missing/package_foo_index.json
@@ -0,0 +1,56 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2"
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-size-incorrect-type/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-size-incorrect-type/package_foo_index.json
new file mode 100644
index 00000000..66a3c360
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-size-incorrect-type/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": 42,
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-size-invalid/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-size-invalid/package_foo_index.json
new file mode 100644
index 00000000..edd3d73e
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-size-invalid/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "foo",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-size-missing/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-size-missing/package_foo_index.json
new file mode 100644
index 00000000..4600332e
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-size-missing/package_foo_index.json
@@ -0,0 +1,71 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-url-incorrect-type/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-url-incorrect-type/package_foo_index.json
new file mode 100644
index 00000000..59378aa3
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-url-incorrect-type/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": 42
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-url-invalid-format/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-url-invalid-format/package_foo_index.json
new file mode 100644
index 00000000..b7c17630
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-url-invalid-format/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "foo"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-url-missing/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-url-missing/package_foo_index.json
new file mode 100644
index 00000000..abc17024
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-systems-url-missing/package_foo_index.json
@@ -0,0 +1,71 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "0.11.0-arduino2",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-version-incorrect-type/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-version-incorrect-type/package_foo_index.json
new file mode 100644
index 00000000..b9b1911c
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-version-incorrect-type/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": 1.23,
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-version-missing/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-version-missing/package_foo_index.json
new file mode 100644
index 00000000..c6f77876
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-version-missing/package_foo_index.json
@@ -0,0 +1,71 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-version-non-relaxed-semver/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-version-non-relaxed-semver/package_foo_index.json
new file mode 100644
index 00000000..ab405a53
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-version-non-relaxed-semver/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "foo",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/internal/rule/rulefunction/testdata/packageindexes/packages-tools-version-not-semver/package_foo_index.json b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-version-not-semver/package_foo_index.json
new file mode 100644
index 00000000..07be9277
--- /dev/null
+++ b/internal/rule/rulefunction/testdata/packageindexes/packages-tools-version-not-semver/package_foo_index.json
@@ -0,0 +1,72 @@
+{
+  "packages": [
+    {
+      "name": "foopackager",
+      "maintainer": "Jane Developer",
+      "websiteURL": "http://example.com",
+      "email": "jane@example.com",
+      "help": {
+        "online": "http://example.com"
+      },
+      "platforms": [
+        {
+          "name": "My Board",
+          "architecture": "avr",
+          "version": "1.0.0",
+          "category": "Contributed",
+          "help": {
+            "online": "http://example.com"
+          },
+          "url": "http://example.com",
+          "archiveFileName": "myboard-1.0.0.zip",
+          "checksum": "MD5:6c0f556759894aa1a45e8af423a08ce8",
+          "size": "15005",
+          "boards": [],
+          "toolsDependencies": []
+        }
+      ],
+      "tools": [
+        {
+          "name": "openocd",
+          "version": "1.0",
+          "systems": [
+            {
+              "size": "1902818",
+              "checksum": "SHA-256:a1aa7f1435a61eafb72ee90722f2496d6a34a7a0f085d0315c2613e4a548b824",
+              "host": "aarch64-linux-gnu",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-aarch64-linux-gnu.tar.bz2",
+              "url": "http://example.com"
+            },
+            {
+              "size": "1986716",
+              "checksum": "SHA-256:57041130160be086e69387cceb4616eefc9819a0ef75de1f7c11aea57fb92699",
+              "host": "arm-linux-gnueabihf",
+              "archiveFileName": "openocd-0.11.0-arduino2-static-arm-linux-gnueabihf.tar.bz2",
+              "url": "http://example.com"
+            }
+          ]
+        },
+        {
+          "name": "CMSIS",
+          "version": "4.0.0-atmel",
+          "systems": [
+            {
+              "host": "arm-linux-gnueabihf",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://example.com",
+              "archiveFileName": "CMSIS-4.0.0.tar.bz2",
+              "checksum": "SHA-256:7d637d2d7a0c6bacc22065848a201db2fff124268e4a56868260d0f472b4bbb7",
+              "size": "17642623"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}