diff --git a/pyrit/executor/promptgen/gcg/attack/base/attack_manager.py b/pyrit/executor/promptgen/gcg/attack/base/attack_manager.py index efd0fc7f30..25b497b9a1 100644 --- a/pyrit/executor/promptgen/gcg/attack/base/attack_manager.py +++ b/pyrit/executor/promptgen/gcg/attack/base/attack_manager.py @@ -1819,7 +1819,7 @@ class ModelWorker: def __init__( self, model_path: str, - token: str, + token: str | None, model_kwargs: dict[str, Any], tokenizer: Any, device: str, diff --git a/pyrit/executor/promptgen/gcg/generator.py b/pyrit/executor/promptgen/gcg/generator.py index 4c6550293e..14995110ff 100644 --- a/pyrit/executor/promptgen/gcg/generator.py +++ b/pyrit/executor/promptgen/gcg/generator.py @@ -410,7 +410,10 @@ def _to_attack_params(self, *, context: GCGContext) -> Any: all_models = self._models + self._test_models return SimpleNamespace( - token=self._hf_token or "", + # None means anonymous access. An empty string makes huggingface_hub send + # "Authorization: Bearer " with no credential, which httpx rejects as an + # illegal header value, so public models would fail to load. + token=self._hf_token, tokenizer_paths=[m.name for m in all_models], tokenizer_kwargs=[m.tokenizer_kwargs for m in all_models], model_paths=[m.name for m in all_models], diff --git a/tests/unit/executor/promptgen/gcg/test_generator.py b/tests/unit/executor/promptgen/gcg/test_generator.py index f35e90db9a..af19732a06 100644 --- a/tests/unit/executor/promptgen/gcg/test_generator.py +++ b/tests/unit/executor/promptgen/gcg/test_generator.py @@ -158,6 +158,27 @@ def test_test_length_mismatch_raises(self) -> None: ) +class TestToAttackParamsToken: + """The HuggingFace token forwarded to model loading.""" + + def test_token_is_none_when_not_supplied(self) -> None: + # An empty string makes huggingface_hub send "Authorization: Bearer " with no + # credential, which httpx rejects as an illegal header value. None means anonymous, + # which is what loading a public model needs. + gen = GCGGenerator(models=[GCGModelConfig(name=_LLAMA_2)]) + + params = gen._to_attack_params(context=GCGContext(goals=["g"], targets=["t"])) + + assert params.token is None + + def test_token_is_forwarded_when_supplied(self) -> None: + gen = GCGGenerator(models=[GCGModelConfig(name=_LLAMA_2)], hf_token="hf_example") + + params = gen._to_attack_params(context=GCGContext(goals=["g"], targets=["t"])) + + assert params.token == "hf_example" + + @pytest.fixture def patched_get_workers(): """Patch the heavy worker spawn so lifecycle tests don't try to load real models."""