Skip to content

Fix UnboundLocalError in fetch_v2fly_domains when domain file fails to parse - #290

Open
msarg44 wants to merge 1 commit into
blacklanternsecurity:stablefrom
msarg44:fix-v2fly-domains-unboundlocalerror
Open

Fix UnboundLocalError in fetch_v2fly_domains when domain file fails to parse#290
msarg44 wants to merge 1 commit into
blacklanternsecurity:stablefrom
msarg44:fix-v2fly-domains-unboundlocalerror

Conversation

@msarg44

@msarg44 msarg44 commented Aug 25, 2026

Copy link
Copy Markdown

Summary

BaseProvider.fetch_v2fly_domains() in cloudcheck/providers/base.py only assigns the local domains variable inside the try block:

errors = []
repo_path, _success = self._ensure_v2fly_repo_cached()
company_file = repo_path / "data" / self.v2fly_company
try:
    domains = parse_v2fly_domain_file(company_file)
except Exception as e:
    errors.append(
        f"Failed to parse {self.v2fly_company} domains: {e}:\n{traceback.format_exc()}"
    )
return sorted(list(domains)), errors

If parse_v2fly_domain_file() raises (e.g. the v2fly community repo clone fails, or the company's data/<company> file is missing/unreadable), the except branch correctly appends the error, but domains was never bound. The final return sorted(list(domains)), errors then raises UnboundLocalError, crashing the whole domain-update pass for the provider — even though a perfectly good error message was already collected.

Change

Initialize domains = set() before the try block so the failure path returns the collected error plus empty domains instead of crashing:

errors = []
domains = set()
repo_path, _success = self._ensure_v2fly_repo_cached()
company_file = repo_path / "data" / self.v2fly_company
try:
    domains = parse_v2fly_domain_file(company_file)
except Exception as e:
    errors.append(
        f"Failed to parse {self.v2fly_company} domains: {e}:\n{traceback.format_exc()}"
    )
return sorted(list(domains)), errors

This matches the documented contract (fetch_v2fly_domains() returns (domains, errors)) — downstream callers in update_domains() already handle per-provider errors gracefully.

Testing

Added a regression test test_v2fly_domains_missing_file in cloudcheck_update/test_cloudcheck_update.py that patches parse_v2fly_domain_file to raise, then asserts the call returns ([], [error]) rather than crashing with UnboundLocalError.

…o parse

The try/except in fetch_v2fly_domains only assigned 'domains' inside the
try block. If parse_v2fly_domain_file raised (e.g. the v2fly repo clone
fails or a company file is missing/unreadable), the except branch appended
the error but 'domains' was never bound, so 'sorted(list(domains))' on the
final line raised UnboundLocalError and crashed the update regardless of
the (correctly) collected error.

Initialize 'domains = set()' before the try so the except path returns
empty domains plus the error instead of crashing. Adds a regression test
verifying graceful handling when the domain file cannot be parsed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant