diff --git a/ctfcli/core/challenge.py b/ctfcli/core/challenge.py index 0226c51..32a41a9 100644 --- a/ctfcli/core/challenge.py +++ b/ctfcli/core/challenge.py @@ -263,7 +263,7 @@ def create(self, ignore: tuple[str] = ()) -> None: if not self.get("name", False): raise InvalidChallengeDefinition("Challenge does not provide a name") - if not self.get("value", False) and self.get("type", "standard") != "dynamic": + if self.get("value") is None and self.get("type", "standard") != "dynamic": raise InvalidChallengeDefinition("Challenge does not provide a value") ctx = PropertyContext(self, ignore=ignore) diff --git a/tests/core/test_challenge.py b/tests/core/test_challenge.py index a0bd7be..a54e9b2 100644 --- a/tests/core/test_challenge.py +++ b/tests/core/test_challenge.py @@ -9,6 +9,7 @@ from ctfcli.core.challenge import Challenge from ctfcli.core.exceptions import ( + InvalidChallengeDefinition, InvalidChallengeFile, LintException, RemoteChallengeNotFound, @@ -2096,6 +2097,28 @@ def mock_post(*args, **kwargs): mock_api.get.assert_not_called() mock_api.delete.assert_not_called() + @mock.patch("ctfcli.core.challenge.API") + def test_creates_challenge_with_zero_value(self, mock_api_constructor: MagicMock, *args, **kwargs): + challenge = Challenge(self.minimal_challenge, {"value": 0}) + + mock_api: MagicMock = mock_api_constructor.return_value + mock_api.post.return_value.json.return_value = {"success": True, "data": {"id": 3}} + + challenge.create() + + mock_api.post.assert_called_once_with("/api/v1/challenges", json=ANY) + self.assertEqual(mock_api.post.call_args.kwargs["json"]["value"], 0) + + @mock.patch("ctfcli.core.challenge.API") + def test_does_not_create_challenge_without_value(self, mock_api_constructor: MagicMock, *args, **kwargs): + challenge = Challenge(self.minimal_challenge, {"value": None}) + + with self.assertRaises(InvalidChallengeDefinition) as e: + challenge.create() + + self.assertEqual(str(e.exception), "Challenge does not provide a value") + mock_api_constructor.return_value.post.assert_not_called() + class TestLintChallenge(unittest.TestCase): minimal_challenge = BASE_DIR / "fixtures" / "challenges" / "test-challenge-minimal" / "challenge.yml"