Skip to content

Commit 763c2de

Browse files
fuyu0425ColdHeat
andauthored
Set challenge attribution (#164)
* Handle challenge attribution and its related tests * Update upload-artifact to v3 --------- Co-authored-by: Kevin Chung <[email protected]>
1 parent d8e08da commit 763c2de

File tree

8 files changed

+43
-14
lines changed

8 files changed

+43
-14
lines changed

.github/workflows/release.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
- name: Build package
3434
run: poetry build
3535

36-
- uses: actions/upload-artifact@v2
36+
- uses: actions/upload-artifact@v3
3737
with:
3838
path: |
3939
./dist/*.tar.gz

ctfcli/core/challenge.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def str_presenter(dumper, data):
4343
class Challenge(dict):
4444
key_order = [
4545
# fmt: off
46-
"name", "author", "category", "description", "value",
46+
"name", "author", "category", "description", "attribution", "value",
4747
"type", "extra", "image", "protocol", "host",
4848
"connection_info", "healthcheck", "attempts", "flags",
4949
"files", "topics", "tags", "files", "hints",
@@ -262,6 +262,7 @@ def _get_initial_challenge_payload(self, ignore: Tuple[str] = ()) -> Dict:
262262
"name": self["name"],
263263
"category": self.get("category", ""),
264264
"description": self.get("description", ""),
265+
"attribution": self.get("attribution", ""),
265266
"type": self.get("type", "standard"),
266267
# Hide the challenge for the duration of the sync / creation
267268
"state": "hidden",
@@ -459,12 +460,13 @@ def normalize_requirements(requirements):
459460
def _normalize_challenge(self, challenge_data: Dict[str, Any]):
460461
challenge = {}
461462

462-
copy_keys = ["name", "category", "value", "type", "state", "connection_info"]
463+
copy_keys = ["name", "category", "attribution", "value", "type", "state", "connection_info"]
463464
for key in copy_keys:
464465
if key in challenge_data:
465466
challenge[key] = challenge_data[key]
466467

467468
challenge["description"] = challenge_data["description"].strip().replace("\r\n", "\n").replace("\t", "")
469+
challenge["attribution"] = challenge_data.get("attribution", "").strip().replace("\r\n", "\n").replace("\t", "")
468470
challenge["attempts"] = challenge_data["max_attempts"]
469471

470472
for key in ["initial", "decay", "minimum"]:
@@ -556,7 +558,7 @@ def sync(self, ignore: Tuple[str] = ()) -> None:
556558
remote_challenge = self.load_installed_challenge(self.challenge_id)
557559

558560
# if value, category, type or description are ignored, revert them to the remote state in the initial payload
559-
reset_properties_if_ignored = ["value", "category", "type", "description"]
561+
reset_properties_if_ignored = ["value", "category", "type", "description", "attribution"]
560562
for p in reset_properties_if_ignored:
561563
if p in ignore:
562564
challenge_payload[p] = remote_challenge[p]
@@ -670,7 +672,7 @@ def create(self, ignore: Tuple[str] = ()) -> None:
670672
# value is required (unless the challenge is a dynamic value challenge),
671673
# and the type will default to standard
672674
# if category or description are ignored, set them to an empty string
673-
reset_properties_if_ignored = ["category", "description"]
675+
reset_properties_if_ignored = ["category", "description", "attribution"]
674676
for p in reset_properties_if_ignored:
675677
if p in ignore:
676678
challenge_payload[p] = ""
@@ -716,7 +718,7 @@ def lint(self, skip_hadolint=False, flag_format="flag{") -> bool:
716718
issues = {"fields": [], "dockerfile": [], "hadolint": [], "files": []}
717719

718720
# Check if required fields are present
719-
for field in ["name", "author", "category", "description", "value"]:
721+
for field in ["name", "author", "category", "description", "attribution", "value"]:
720722
# value is allowed to be none if the challenge type is dynamic
721723
if field == "value" and challenge.get("type") == "dynamic":
722724
continue

tests/core/test_challenge.py

+26-4
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ def test_updates_simple_properties(self, mock_api_constructor: MagicMock, *args,
197197
"name": "Test Challenge",
198198
"category": "New Test",
199199
"description": "New Test Description",
200+
"attribution": "New Test Attribution",
200201
"type": "standard",
201202
"value": 150,
202203
"state": "hidden",
@@ -239,6 +240,7 @@ def test_updates_attempts(self, mock_api_constructor: MagicMock, *args, **kwargs
239240
"name": "Test Challenge",
240241
"category": "New Test",
241242
"description": "New Test Description",
243+
"attribution": "New Test Attribution",
242244
"type": "standard",
243245
"value": 150,
244246
"state": "hidden",
@@ -284,6 +286,7 @@ def test_updates_extra_properties(self, mock_api_constructor: MagicMock, *args,
284286
"name": "Test Challenge",
285287
"category": "New Test",
286288
"description": "New Test Description",
289+
"attribution": "New Test Attribution",
287290
"value": 150,
288291
"state": "hidden",
289292
"type": "application_target",
@@ -342,6 +345,7 @@ def test_updates_flags(self, mock_api_constructor: MagicMock, *args, **kwargs):
342345
"name": "Test Challenge",
343346
"category": "New Test",
344347
"description": "New Test Description",
348+
"attribution": "New Test Attribution",
345349
"type": "standard",
346350
"value": 150,
347351
"state": "hidden",
@@ -430,6 +434,7 @@ def test_updates_topics(self, mock_api_constructor: MagicMock, *args, **kwargs):
430434
"name": "Test Challenge",
431435
"category": "New Test",
432436
"description": "New Test Description",
437+
"attribution": "New Test Attribution",
433438
"type": "standard",
434439
"value": 150,
435440
"state": "hidden",
@@ -490,6 +495,7 @@ def test_updates_tags(self, mock_api_constructor: MagicMock, *args, **kwargs):
490495
"name": "Test Challenge",
491496
"category": "New Test",
492497
"description": "New Test Description",
498+
"attribution": "New Test Attribution",
493499
"type": "standard",
494500
"value": 150,
495501
"state": "hidden",
@@ -553,6 +559,7 @@ def test_updates_files(self, mock_api_constructor: MagicMock, *args, **kwargs):
553559
"name": "Test Challenge",
554560
"category": "New Test",
555561
"description": "New Test Description",
562+
"attribution": "New Test Attribution",
556563
"type": "standard",
557564
"value": 150,
558565
"state": "hidden",
@@ -654,6 +661,7 @@ def test_updates_hints(self, mock_api_constructor: MagicMock, *args, **kwargs):
654661
"name": "Test Challenge",
655662
"category": "New Test",
656663
"description": "New Test Description",
664+
"attribution": "New Test Attribution",
657665
"type": "standard",
658666
"value": 150,
659667
"state": "hidden",
@@ -714,6 +722,7 @@ def test_updates_requirements(self, mock_api_constructor: MagicMock, *args, **kw
714722
"name": "Test Challenge",
715723
"category": "New Test",
716724
"description": "New Test Description",
725+
"attribution": "New Test Attribution",
717726
"type": "standard",
718727
"value": 150,
719728
"state": "hidden",
@@ -756,6 +765,7 @@ def test_challenge_cannot_require_itself(
756765
"name": "Test Challenge",
757766
"category": "New Test",
758767
"description": "New Test Description",
768+
"attribution": "New Test Attribution",
759769
"type": "standard",
760770
"value": 150,
761771
"state": "hidden",
@@ -816,6 +826,7 @@ def test_defaults_to_standard_challenge_type(self, mock_api_constructor: MagicMo
816826
"name": "Test Challenge",
817827
"category": "New Test",
818828
"description": "New Test Description",
829+
"attribution": "New Test Attribution",
819830
"type": "standard",
820831
"value": 150,
821832
"state": "hidden",
@@ -854,6 +865,7 @@ def test_defaults_to_visible_state(self, mock_api_constructor: MagicMock, *args,
854865
"name": "Test Challenge",
855866
"category": "New Test",
856867
"description": "New Test Description",
868+
"attribution": "New Test Attribution",
857869
"type": "standard",
858870
"value": 150,
859871
"max_attempts": 0,
@@ -904,6 +916,7 @@ def test_does_not_update_dynamic_value(self, mock_api_constructor: MagicMock, *a
904916
"name": "Test Challenge",
905917
"category": "New Test",
906918
"description": "New Test Description",
919+
"attribution": "New Test Attribution",
907920
"type": "dynamic",
908921
"state": "hidden",
909922
"max_attempts": 0,
@@ -961,6 +974,7 @@ def test_updates_multiple_attributes_at_once(self, mock_api_constructor: MagicMo
961974
"name": "Test Challenge",
962975
"category": "New Test",
963976
"description": "New Test Description",
977+
"attribution": "New Test Attribution",
964978
"type": "standard",
965979
"value": 150,
966980
"state": "hidden",
@@ -1018,7 +1032,7 @@ def test_does_not_update_ignored_attributes(self):
10181032
properties = [
10191033
# fmt: off
10201034
# simple types
1021-
"category", "description", "type", "value", "attempts", "connection_info", "state",
1035+
"category", "description", "attribution", "type", "value", "attempts", "connection_info", "state",
10221036
# complex types
10231037
"extra", "flags", "topics", "tags", "files", "hints", "requirements",
10241038
# fmt: on
@@ -1028,6 +1042,7 @@ def test_does_not_update_ignored_attributes(self):
10281042
"name": "Test Challenge",
10291043
"category": "Old Category",
10301044
"description": "Old Description",
1045+
"attribution": "Old Attribution",
10311046
"type": "some-custom-type",
10321047
"value": 100,
10331048
"state": "visible",
@@ -1057,6 +1072,7 @@ def test_does_not_update_ignored_attributes(self):
10571072
"name": "Test Challenge",
10581073
"category": "New Test",
10591074
"description": "New Test Description",
1075+
"attribution": "New Test Attribution",
10601076
"type": "standard",
10611077
"value": 150,
10621078
"state": "hidden",
@@ -1072,7 +1088,7 @@ def test_does_not_update_ignored_attributes(self):
10721088
expected_challenge_payload["value"] = remote_installed_challenge["value"]
10731089
challenge["value"] = 200
10741090

1075-
if p in ["category", "description", "type"]:
1091+
if p in ["category", "description", "attribution", "type"]:
10761092
expected_challenge_payload[p] = remote_installed_challenge[p]
10771093
challenge[p] = "new-value"
10781094

@@ -1154,6 +1170,7 @@ def test_creates_standard_challenge(self, mock_api_constructor: MagicMock, *args
11541170
"name": "Test Challenge",
11551171
"category": "Test",
11561172
"description": "Test Description",
1173+
"attribution": "Test Attribution",
11571174
"value": 150,
11581175
"max_attempts": 5,
11591176
"type": "standard",
@@ -1244,7 +1261,7 @@ def test_exits_if_files_do_not_exist(self, mock_api_constructor: MagicMock, *arg
12441261
def test_does_not_set_ignored_attributes(self):
12451262
# fmt:off
12461263
properties = [
1247-
"value", "category", "description", "attempts", "connection_info", "state", # simple types
1264+
"value", "category", "description", "attribution", "attempts", "connection_info", "state", # simple types
12481265
"extra", "flags", "topics", "tags", "files", "hints", "requirements" # complex types
12491266
]
12501267
# fmt:on
@@ -1262,6 +1279,7 @@ def test_does_not_set_ignored_attributes(self):
12621279
"name": "Test Challenge",
12631280
"category": "New Test",
12641281
"description": "New Test Description",
1282+
"attribution": "New Test Attribution",
12651283
"type": "standard",
12661284
"value": 150,
12671285
"state": "hidden",
@@ -1282,7 +1300,7 @@ def test_does_not_set_ignored_attributes(self):
12821300
expected_challenge_payload[p] = "custom-type"
12831301

12841302
# expect these to be in the payload, with the defaults or empty:
1285-
if p in ["category", "description"]:
1303+
if p in ["category", "description", "attribution"]:
12861304
challenge[p] = "new-value"
12871305
expected_challenge_payload[p] = ""
12881306

@@ -1520,6 +1538,7 @@ def mock_get(self, *args, **kwargs):
15201538
"name": "Test Challenge",
15211539
"value": 150,
15221540
"description": "Test Description",
1541+
"attribution": "Test Attribution",
15231542
"connection_info": "https://example.com",
15241543
"next_id": None,
15251544
"category": "Test",
@@ -1681,6 +1700,7 @@ def test_normalize_fetches_and_normalizes_challenge(self, mock_api_constructor:
16811700
"name": "Test Challenge",
16821701
"category": "Test",
16831702
"description": "Test Description",
1703+
"attribution": "Test Attribution",
16841704
"value": 150,
16851705
"max_attempts": 5,
16861706
"type": "standard",
@@ -1703,6 +1723,7 @@ def test_normalize_fetches_and_normalizes_challenge(self, mock_api_constructor:
17031723
"state": "hidden",
17041724
"connection_info": "https://example.com",
17051725
"description": "Test Description",
1726+
"attribution": "Test Attribution",
17061727
"attempts": 5,
17071728
"flags": [
17081729
"flag{test-flag}",
@@ -1755,6 +1776,7 @@ def test_mirror_challenge(self, mock_api_constructor: MagicMock):
17551776
{
17561777
"value": 200,
17571778
"description": "other description",
1779+
"attribution": "other attribution",
17581780
"connection_info": "https://other.example.com",
17591781
"flags": ["flag{other-flag}", "other-flag"],
17601782
"topics": ["other-topic-1", "other-topic-2"],
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
name: Test Challenge
22
category: New Test
33
description: New Test Description
4+
attribution: New Test Attribution
45
value: 150
56
author: Test
67
type: standard
78
state: hidden
89
image: .
9-
protocol: http
10+
protocol: http
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
name: Test Challenge
22
category: New Test
33
description: New Test Description
4+
attribution: New Test Attribution
45
value: 150
56
author: Test
67
type: standard
78
state: hidden
89

910
files:
1011
- files/test.png
11-
- files/test.pdf
12+
- files/test.pdf

tests/fixtures/challenges/test-challenge-full/challenge.yml

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
name: Test Challenge
22
category: Test
33
description: Test Description
4+
attribution: Test Attribution
45
value: 150
56
author: Test
67
type: standard
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
name: Test Challenge
22
category: New Test
33
description: New Test Description
4+
attribution: New Test Attribution
45
value: 150
56
author: Test
67
type: standard
78
state: hidden
8-
image: .
9+
image: .
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
name: Test Challenge
22
category: New Test
33
description: New Test Description
4+
attribution: New Test Attribution
45
value: 150
56
author: Test
67
type: standard
7-
state: hidden
8+
state: hidden

0 commit comments

Comments
 (0)