Skip to content

Commit

Permalink
Merge branch 'master' into sf-handle-untracked-files-in-contrib-pr
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelFain committed Jun 19, 2024
2 parents 7c42e8d + d35f9d9 commit dcec540
Show file tree
Hide file tree
Showing 11 changed files with 448 additions and 10 deletions.
4 changes: 4 additions & 0 deletions .changelog/4287.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
changes:
- description: Added a fix where the `auto_update_docker_image` field was not updated correctly in the the content-graph.
type: fix
pr_number: 4287
4 changes: 4 additions & 0 deletions .changelog/4358.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
changes:
- description: Moved PB109 to the new validate format. The validation checks that taskid field and id field under task field contains equal values.
type: internal
pr_number: 4358
4 changes: 4 additions & 0 deletions .changelog/4360.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
changes:
- description: Converted PB106 validation to new validation format. The validation checks if the playbook uses a specific instance.
type: internal
pr_number: 4360
4 changes: 4 additions & 0 deletions .changelog/4366.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
changes:
- description: Converted PB115 validation to new validation format. The validation checks if the 'quietmode' field of all tasks in playbook are not in default value.
type: internal
pr_number: 4366
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,4 @@ def subtype(self):

@property
def auto_update_docker_image(self):
return (
get_value(self.yml_data, "autoUpdateDockerImage", "")
).lower() != "false"
return get_value(self.yml_data, "autoUpdateDockerImage", True)
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@


def content_items_to_node_ids(
content_items_dict: Dict[ContentType, List[str]]
content_items_dict: Dict[ContentType, List[str]],
) -> Set[str]:
"""A helper method that converts a dict of content items to a set of their node ids."""
return {
Expand Down Expand Up @@ -1272,7 +1272,14 @@ def test_script_parser(self, pack: Pack):

@pytest.mark.parametrize(
"raw_value, expected_value",
[("false", False), ("true", True), ("tRue", True), ("something", True)],
[
(False, False),
(True, True),
("true", True),
("false", False),
("tRue", True),
("faLse", False),
],
)
def test_script_parser_set_autoupdate(self, raw_value, expected_value, pack: Pack):
"""
Expand Down
6 changes: 2 additions & 4 deletions demisto_sdk/commands/validate/sdk_validation_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ select = [
"IN100", "IN101", "IN102", "IN104", "IN106", "IN107", "IN108", "IN109", "IN110", "IN112", "IN113", "IN114", "IN115", "IN117", "IN118", "IN121", "IN122", "IN123", "IN124", "IN125", "IN126", "IN127", "IN130",
"IN131", "IN134", "IN135", "IN139", "IN141", "IN142", "IN144", "IN145", "IN146", "IN149", "IN150", "IN151", "IN152", "IN153", "IN154", "IN156", "IN158", "IN159", "IN160",
"IN161", "IN162",
"PB100", "PB101", "PB103", "PB104", "PB105", "PB108", "PB118", "PB122", "PB123", "PB125", "PB126",
"PB100", "PB101", "PB103", "PB104", "PB105", "PB108", "PB118", "PB122", "PB123", "PB126",
"PB100", "PB101", "PB103", "PB104", "PB105", "PB106", "PB108", "PB109", "PB115", "PB118", "PB122", "PB123", "PB125", "PB126",
"DO100", "DO101", "DO102", "DO103", "DO104", "DO105", "DO106",
"DS100", "DS101", "DS105", "DS106", "DS107",
"SC100", "SC105", "SC106", "SC109",
Expand All @@ -53,8 +52,7 @@ select = [
"IN131", "IN134", "IN135", "IN139", "IN141", "IN142", "IN144", "IN145", "IN146", "IN149", "IN150", "IN151", "IN152", "IN153", "IN154", "IN156", "IN158", "IN159", "IN160",
"IN161", "IN162",
"LO107",
"PB100", "PB101", "PB103", "PB104", "PB105", "PB108", "PB122", "PB123", "PB125", "PB126",
"PB100", "PB101", "PB103", "PB104", "PB105", "PB108", "PB122", "PB123", "PB126",
"PB100", "PB101", "PB103", "PB104", "PB105", "PB106", "PB108", "PB109", "PB115", "PB122", "PB123", "PB125", "PB126",
"BA100", "BA101", "BA105", "BA106", "BA110", "BA111", "BA113", "BA116", "BA118", "BA119", "BA126",
"DS100", "DS101", "DS105",
"PA100", "PA101", "PA102", "PA103", "PA104", "PA105", "PA107", "PA108", "PA109", "PA111", "PA113", "PA115", "PA117", "PA118", "PA119", "PA120",
Expand Down
218 changes: 217 additions & 1 deletion demisto_sdk/commands/validate/tests/PB_validators_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest

from demisto_sdk.commands.content_graph.objects.base_playbook import TaskConfig
from demisto_sdk.commands.content_graph.objects.playbook import Playbook
from demisto_sdk.commands.validate.tests.test_tools import create_playbook_object
from demisto_sdk.commands.validate.validators.PB_validators.PB100_is_no_rolename import (
IsNoRolenameValidator,
Expand All @@ -18,9 +19,18 @@
from demisto_sdk.commands.validate.validators.PB_validators.PB105_playbook_delete_context_all import (
PlaybookDeleteContextAllValidator,
)
from demisto_sdk.commands.validate.validators.PB_validators.PB106_is_playbook_using_an_instance import (
IsPlayBookUsingAnInstanceValidator,
)
from demisto_sdk.commands.validate.validators.PB_validators.PB108_is_valid_task_id import (
IsValidTaskIdValidator,
)
from demisto_sdk.commands.validate.validators.PB_validators.PB109_is_taskid_equals_id import (
IsTaskidDifferentFromidValidator,
)
from demisto_sdk.commands.validate.validators.PB_validators.PB115_is_tasks_quiet_mode import (
IsTasksQuietModeValidator,
)
from demisto_sdk.commands.validate.validators.PB_validators.PB118_is_input_key_not_in_tasks import (
IsInputKeyNotInTasksValidator,
)
Expand Down Expand Up @@ -323,6 +333,110 @@ def test_IsAskConditionHasUnhandledReplyOptionsValidator():
assert IsAskConditionHasUnhandledReplyOptionsValidator().is_valid([playbook])


def test_IsTasksQuietModeValidator_fail_case():
"""
Given:
- A invalid playbook with tasks that "quietmode" field is 2
- An invalid playbook to fix
When:
- calling IsTasksQuietModeValidator.is_valid.
- calling IsTasksQuietModeValidator.fix
Then:
- The playbook is invalid
-The playbook becomes valid
"""
playbook = create_playbook_object(
["inputs", "quiet", "tasks"],
[
[
{
"value": {},
"required": False,
"description": "",
"playbookInputQuery": {"query": "", "queryEntity": "indicators"},
}
],
False,
{
"0": {
"id": "test fail task No1",
"taskid": "27b9c747-b883-4878-8b60-7f352098a631",
"type": "condition",
"message": {"replyOptions": ["yes"]},
"nexttasks": {"no": ["1"]},
"task": {"id": "27b9c747-b883-4878-8b60-7f352098a63c"},
"quietmode": 2,
},
"1": {
"id": "test fail task No2",
"taskid": "27b9c747-b883-4878-8b60-7f352098a631",
"type": "condition",
"message": {"replyOptions": ["yes"]},
"nexttasks": {"no": ["1"]},
"task": {"id": "27b9c747-b883-4878-8b60-7f352098a63c"},
"quietmode": 2,
},
},
],
pack_info={},
)
validator = IsTasksQuietModeValidator()
validate_res = validator.is_valid([playbook])
assert len(validate_res) == 1
assert (
(validate_res[0]).message
== "Playbook 'Detonate File - JoeSecurity V2' contains tasks that are not in quiet mode (quietmode: 2) The tasks names is: 'test fail task No1, test fail task No2'."
)
fix_playbook = validator.fix(playbook).content_object
assert len(validator.is_valid([fix_playbook])) == 0


def test_IsTasksQuietModeValidator_pass_case():
"""
Given:
- A valid playbook with tasks that "quietmode" field is 1
When:
- calling IsTasksQuietModeValidator.is_valid.
- calling IsTasksQuietModeValidator.fix
Then:
- The playbook is valid
- The playbook doesn't changed
"""
playbook = create_playbook_object(
["inputs", "quiet", "tasks"],
[
[
{
"value": {},
"required": False,
"description": "",
"playbookInputQuery": {"query": "", "queryEntity": "indicators"},
}
],
False,
{
"0": {
"id": "test task",
"taskid": "27b9c747-b883-4878-8b60-7f352098a631",
"type": "condition",
"message": {"replyOptions": ["yes"]},
"nexttasks": {"no": ["1"]},
"task": {"id": "27b9c747-b883-4878-8b60-7f352098a63c"},
"quietmode": 1,
}
},
],
)
validator = IsTasksQuietModeValidator()
assert len(validator.is_valid([playbook])) == 0
fix_playbook = validator.fix(playbook).content_object
assert fix_playbook == playbook


def test_PB125_playbook_only_default_next_valid():
"""
Given:
Expand Down Expand Up @@ -585,7 +699,6 @@ def test_IsDefaultNotOnlyConditionValidator():
}
)
}

assert not IsDefaultNotOnlyConditionValidator().is_valid([playbook])
playbook.tasks = {
"0": TaskConfig(
Expand All @@ -599,3 +712,106 @@ def test_IsDefaultNotOnlyConditionValidator():
)
}
assert IsDefaultNotOnlyConditionValidator().is_valid([playbook])


def test_IsTaskidDifferentFromidValidator():
"""
Given:
- A playbook with tasks, taskid and id
Case 1: id equals taskid
Case 2: id not equals taskid
When:
- Validating the playbook
Then:
- The results should be as expected:
Case 1: an empty list
Case 2: a list in length 1 because there is one error
"""
playbook = create_playbook_object()
results = IsTaskidDifferentFromidValidator().is_valid([playbook])
assert len(results) == 0
playbook.tasks = {
"0": TaskConfig(
**{
"id": "test",
"taskid": "test1",
"type": "condition",
"message": {"replyOptions": ["yes"]},
"nexttasks": {"no": ["1"]},
"task": {"id": "test"},
}
)
}
results = IsTaskidDifferentFromidValidator().is_valid([playbook])
assert len(results) == 1
assert (
results[0].message
== "On tasks: 0, the field 'taskid' and the 'id' under the 'task' field must be with equal value."
)


def test_IsPlayBookUsingAnInstanceValidator_is_valid():
"""
Given:
- A playbook
Case 1: The playbook is valid.
Case 2: The playbook isn't valid, it has using field.
When:
- calling IsPlayBookUsingAnInstanceValidator.is_valid.
Then:
- The results should be as expected:
Case 1: The playbook is valid
Case 2: The playbook is invalid
"""
# Case 1
valid_playbook = create_playbook_object()
valid_result = IsPlayBookUsingAnInstanceValidator().is_valid([valid_playbook])

# Case 2
invalid_playbook = create_playbook_object()
for _, task in invalid_playbook.tasks.items():
task.scriptarguments = {"using": "instance_name"}
results_invalid = IsPlayBookUsingAnInstanceValidator().is_valid([invalid_playbook])

assert valid_result == []
assert results_invalid != []
assert results_invalid[0].message == (
"Playbook should not use specific instance for tasks: {0}.".format(
", ".join([task.taskid for task in invalid_playbook.tasks.values()])
)
)


def test_IsPlayBookUsingAnInstanceValidator_fix():
"""
Given:
- A playbook
Case 1: The playbook isn't valid, it will be fixed.
When:
- calling IsPlayBookUsingAnInstanceValidator.fix.
Then:
- The message appears with the invalid tasks.
"""

# Case 1
invalid_playbook = create_playbook_object()
for _, task in invalid_playbook.tasks.items():
task.scriptarguments = {"using": "instance_name", "some_key": "value"}
validator_invalid_playbook = IsPlayBookUsingAnInstanceValidator()
validator_invalid_playbook.invalid_tasks[invalid_playbook.name] = [
task for task in invalid_playbook.tasks.values()
]
fix_validator = validator_invalid_playbook.fix(invalid_playbook)
fix_message = fix_validator.message
fixed_content_item: Playbook = fix_validator.content_object
expected_message = (
"Removed The 'using' statement from the following tasks tasks: {0}.".format(
", ".join([task.taskid for task in invalid_playbook.tasks.values()])
)
)
assert fix_message == expected_message
for tasks in fixed_content_item.tasks.values():
scriptargs = tasks.scriptarguments
assert scriptargs == {"some_key": "value"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from __future__ import annotations

from typing import ClassVar, Dict, Iterable, List

from demisto_sdk.commands.content_graph.objects.base_playbook import TaskConfig
from demisto_sdk.commands.content_graph.objects.playbook import Playbook
from demisto_sdk.commands.validate.validators.base_validator import (
BaseValidator,
FixResult,
ValidationResult,
)

ContentTypes = Playbook


class IsPlayBookUsingAnInstanceValidator(BaseValidator[ContentTypes]):
invalid_tasks: ClassVar[dict] = {}
error_code = "PB106"
description = "Validate whether the playbook does not use an instance. If the Playbook use an instance it is not valid."
rationale = "If the playbook uses a specific instance it can leads to errors because not all the users have the same instance."
error_message = "Playbook should not use specific instance for tasks: {0}."
fix_message = "Removed The 'using' statement from the following tasks tasks: {0}."
related_field = "using"
is_auto_fixable = True

def is_playbook_using_an_instance(
self, content_item: ContentTypes
) -> list[TaskConfig]:
content_item_tasks: Dict[str, TaskConfig] = content_item.tasks
invalid_tasks: list[TaskConfig] = []
for _, task in content_item_tasks.items():
scriptargs = task.scriptarguments
if scriptargs and scriptargs.get("using"):
invalid_tasks.append(task)
self.invalid_tasks[content_item.name] = invalid_tasks
return invalid_tasks

def is_valid(self, content_items: Iterable[ContentTypes]) -> List[ValidationResult]:
return [
ValidationResult(
validator=self,
message=self.error_message.format(
", ".join([task.taskid for task in invalid_tasks])
),
content_object=content_item,
)
for content_item in content_items
if (invalid_tasks := self.is_playbook_using_an_instance(content_item))
]

def fix(self, content_item: ContentTypes) -> FixResult:
invalid_tasks = self.invalid_tasks[content_item.name]
for invalid_task in invalid_tasks:
scriptargs = invalid_task.scriptarguments
if scriptargs and scriptargs.get("using", {}):
scriptargs.pop("using")
return FixResult(
validator=self,
message=self.fix_message.format(
", ".join([task.taskid for task in invalid_tasks])
),
content_object=content_item,
)
Loading

0 comments on commit dcec540

Please sign in to comment.