Skip to content

fix: Crashing when files field is empty #166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 30, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 22 additions & 15 deletions ctfcli/core/challenge.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,8 @@ def _load_challenge_id(self):
raise RemoteChallengeNotFound(f"Could not load remote challenge with name '{self['name']}'")

def _validate_files(self):
# if the challenge defines files, make sure they exist before making any changes to the challenge
for challenge_file in self.get("files", []):
files = self.get("files") or []
for challenge_file in files:
if not (self.challenge_directory / challenge_file).exists():
raise InvalidChallengeFile(f"File {challenge_file} could not be loaded")

Expand Down Expand Up @@ -364,7 +364,9 @@ def _create_file(self, local_path: Path):

def _create_all_files(self):
new_files = []
for challenge_file in self["files"]:

files = self.get("files") or []
for challenge_file in files:
new_files.append(("file", open(self.challenge_directory / challenge_file, mode="rb")))

files_payload = {"challenge_id": self.challenge_id, "type": "challenge"}
Expand Down Expand Up @@ -587,9 +589,12 @@ def sync(self, ignore: Tuple[str] = ()) -> None:

# Create / Upload files
if "files" not in ignore:
self["files"] = self.get("files") or []
remote_challenge["files"] = remote_challenge.get("files") or []

# Get basenames of local files to compare against remote files
local_files = {f.split("/")[-1]: f for f in self.get("files", [])}
remote_files = self._normalize_remote_files(remote_challenge.get("files", []))
local_files = {f.split("/")[-1]: f for f in self["files"]}
remote_files = self._normalize_remote_files(remote_challenge["files"])

# Delete remote files which are no longer defined locally
for remote_file in remote_files:
Expand Down Expand Up @@ -761,8 +766,8 @@ def lint(self, skip_hadolint=False, flag_format="flag{") -> bool:
click.secho("Skipping Hadolint", fg="yellow")

# Check that all files exist
challenge_files = challenge.get("files", [])
for challenge_file in challenge_files:
files = self.get("files") or []
for challenge_file in files:
challenge_file_path = self.challenge_directory / challenge_file

if challenge_file_path.is_file() is False:
Expand All @@ -771,8 +776,7 @@ def lint(self, skip_hadolint=False, flag_format="flag{") -> bool:
)

# Check that files don't have a flag in them
challenge_files = challenge.get("files", [])
for challenge_file in challenge_files:
for challenge_file in files:
challenge_file_path = self.challenge_directory / challenge_file

if not challenge_file_path.exists():
Expand All @@ -794,9 +798,12 @@ def mirror(self, files_directory_name: str = "dist", ignore: Tuple[str] = ()) ->
remote_challenge = self.load_installed_challenge(self.challenge_id)
challenge = self._normalize_challenge(remote_challenge)

remote_challenge["files"] = remote_challenge.get("files") or []
challenge["files"] = challenge.get("files") or []

# Add files which are not handled in _normalize_challenge
if "files" not in ignore:
local_files = {Path(f).name: f for f in challenge.get("files", [])}
local_files = {Path(f).name: f for f in challenge["files"]}

# Update files
for remote_file in remote_challenge["files"]:
Expand All @@ -813,9 +820,6 @@ def mirror(self, files_directory_name: str = "dist", ignore: Tuple[str] = ()) ->
challenge_files_directory.mkdir(parents=True, exist_ok=True)

(challenge_files_directory / remote_file_name).write_bytes(r.content)
if "files" not in challenge:
challenge["files"] = []

challenge["files"].append(f"{files_directory_name}/{remote_file_name}")

# The file is already present in the challenge.yml - we know the desired path
Expand All @@ -827,7 +831,7 @@ def mirror(self, files_directory_name: str = "dist", ignore: Tuple[str] = ()) ->
# Soft-Delete files that are not present on the remote
# Remove them from challenge.yml but do not delete them from disk
remote_file_names = [f.split("/")[-1].split("?token=")[0] for f in remote_challenge["files"]]
challenge["files"] = [f for f in challenge.get("files", []) if Path(f).name in remote_file_names]
challenge["files"] = [f for f in challenge["files"] if Path(f).name in remote_file_names]

for key in challenge.keys():
if key not in ignore:
Expand All @@ -841,6 +845,9 @@ def verify(self, ignore: Tuple[str] = ()) -> bool:
remote_challenge = self.load_installed_challenge(self.challenge_id)
normalized_challenge = self._normalize_challenge(remote_challenge)

remote_challenge["files"] = remote_challenge.get("files") or []
challenge["files"] = challenge.get("files") or []

for key in normalized_challenge:
if key in ignore:
continue
Expand All @@ -865,7 +872,7 @@ def verify(self, ignore: Tuple[str] = ()) -> bool:
# Check if files defined in challenge.yml are present
try:
self._validate_files()
local_files = {Path(f).name: f for f in challenge.get("files", [])}
local_files = {Path(f).name: f for f in challenge["files"]}
except InvalidChallengeFile:
return False

Expand Down
Loading