Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion api/oss/src/apis/fastapi/access/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def _is_platform_runtime(request: Request) -> bool:
if not expected or expected == _UNCONFIGURED_KEY:
return False

return compare_digest(presented, expected)
return compare_digest(presented.encode("utf-8"), expected.encode("utf-8"))


def _run_credential_grants(request: Request, *, action: Optional[str]) -> List[str]:
Expand Down
5 changes: 3 additions & 2 deletions api/oss/src/apis/fastapi/providers/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ async def _merge_stored_secret(
stored_extras = getattr(settings, "extras", None) if settings else None
stored_key = _stored_credential(secret, settings, stored_extras)

if kind is not None and kind != stored_kind and typed.key is None:
typed_key = _typed_or_stored(typed.key, None)
if kind is not None and kind != stored_kind and typed_key is None:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
detail=(
Expand All @@ -133,7 +134,7 @@ async def _merge_stored_secret(
)

merged = ProviderCredentials(
key=_typed_or_stored(typed.key, stored_key),
key=_typed_or_stored(typed_key, stored_key),
url=_typed_or_stored(typed.url, getattr(settings, "url", None)),
version=_typed_or_stored(typed.version, getattr(settings, "version", None)),
extras=_merged_extras(typed.extras, stored_extras),
Expand Down
9 changes: 9 additions & 0 deletions api/oss/tests/pytest/unit/access/test_grant_exchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,15 @@ async def test_a_wrong_runtime_key_is_not_the_runtime(exchange):
assert "grants" not in _claims(body["credentials"])


@pytest.mark.asyncio
async def test_a_non_ascii_runtime_key_is_not_the_runtime(exchange):
run, _ = exchange

body = _body(await run("run_service", runtime_key="not-the-key-ÿ"))

assert "grants" not in _claims(body["credentials"])


@pytest.mark.asyncio
async def test_the_runtime_key_only_grants_a_run_exchange(exchange):
run, _ = exchange
Expand Down
32 changes: 25 additions & 7 deletions api/oss/tests/pytest/unit/providers/test_provider_probe.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
)
from oss.src.core.providers.service import ProviderProbeService
from oss.src.core.secrets.managed import SecretManagementDTO, SecretManager
from oss.src.core.secrets.enums import SecretKind
from oss.src.core.secrets.redaction import PRIMARY_CREDENTIAL_FIELDS


CANARY = "sk-CANARY-DO-NOT-LEAK-abc123"
Expand Down Expand Up @@ -916,6 +918,27 @@ def test_the_stored_key_is_not_lent_to_another_provider(monkeypatch):
assert STORED_KEY not in response.text


def test_a_blank_key_does_not_lend_the_stored_key_to_another_provider(monkeypatch):
vault = _StubVault()
secret_id = uuid4()
vault.store(secret_id, PROJECT_ID, _stored_provider_key(kind="openai"))
recorder = Recorder(json_response({"data": []}))
client = build_client(monkeypatch, recorder, vault=vault)

response = client.post(
"/providers/probe",
json={
"secret_id": str(secret_id),
"kind": "anthropic",
"provider": {"key": ""},
},
)

assert response.status_code == 422
assert recorder.requests == []
assert STORED_KEY not in response.text


def test_a_kind_change_is_allowed_when_the_caller_brings_the_credential(monkeypatch):
vault = _StubVault()
secret_id = uuid4()
Expand Down Expand Up @@ -1134,13 +1157,8 @@ def test_a_bedrock_connection_probes_with_its_stored_extras_credential(
assert STORED_KEY not in response.text


def test_every_secret_kind_the_classifier_knows_has_a_credential_location():
# The probe asks the classifier where a kind keeps its credential. If a kind is ever
# added to the vault without an entry there, this probe would silently send nothing.
from oss.src.core.secrets.redaction import PRIMARY_CREDENTIAL_FIELDS

assert PRIMARY_CREDENTIAL_FIELDS["provider_key"] == ("provider", "key")
assert PRIMARY_CREDENTIAL_FIELDS["custom_provider"] == ("provider", "key")
def test_every_secret_kind_has_a_credential_location():
assert set(PRIMARY_CREDENTIAL_FIELDS) == {kind.value for kind in SecretKind}


@pytest.mark.parametrize("path", ["/providers/probe", "/vault/v1/providers/probe"])
Expand Down
45 changes: 39 additions & 6 deletions clients/python/agenta_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@
ConfigResponseModel,
ConnectAffordance,
ConnectionRequirement,
CredentialResult,
CredentialStatus,
CustomModelSettingsDto,
CustomProviderDto,
CustomProviderKind,
Expand All @@ -154,6 +156,8 @@
DiscoveredTriggerAlternative,
DiscoveredTriggerEvent,
DiscoveredTriggerEventType,
DiscoveryResult,
DiscoveryStatus,
EntityRef,
Environment,
EnvironmentCreate,
Expand Down Expand Up @@ -374,8 +378,13 @@
OrganizationUpdate,
Permission,
PlaygroundBuildKitContext,
ProbeProviderResponse,
ProjectsResponse,
ProviderCredentials,
PublicMountCreate,
PublicSecretManagementDto,
PublicSecretResponseDto,
PublicSecretResponseDtoData,
QueriesResponse,
Query,
QueryCreate,
Expand Down Expand Up @@ -410,8 +419,8 @@
SecretDto,
SecretDtoData,
SecretKind,
SecretResponseDto,
SecretResponseDtoData,
SecretManagementPolicy,
SecretValueStatus,
Selector,
SessionAttachment,
SessionAttachmentResponse,
Expand Down Expand Up @@ -723,6 +732,8 @@
TriggerSubscriptionQuery,
TriggerSubscriptionResponse,
TriggerSubscriptionsResponse,
UpdateSecretPayloadDto,
UpdateSecretPayloadDtoData,
UserIdsResponse,
ValidationError,
ValidationErrorLocItem,
Expand Down Expand Up @@ -1002,6 +1013,8 @@
"ConfigResponseModel": ".types",
"ConnectAffordance": ".types",
"ConnectionRequirement": ".types",
"CredentialResult": ".types",
"CredentialStatus": ".types",
"CreateSimpleTestsetFromFileRequestFileType": ".testsets",
"CreateTestsetRevisionFromFileRequestFileType": ".testsets",
"CustomModelSettingsDto": ".types",
Expand All @@ -1022,6 +1035,8 @@
"DiscoveredTriggerAlternative": ".types",
"DiscoveredTriggerEvent": ".types",
"DiscoveredTriggerEventType": ".types",
"DiscoveryResult": ".types",
"DiscoveryStatus": ".types",
"EditSimpleTestsetFromFileRequestFileType": ".testsets",
"EntityRef": ".types",
"Environment": ".types",
Expand Down Expand Up @@ -1248,8 +1263,13 @@
"OrganizationUpdate": ".types",
"Permission": ".types",
"PlaygroundBuildKitContext": ".types",
"ProbeProviderResponse": ".types",
"ProjectsResponse": ".types",
"ProviderCredentials": ".types",
"PublicMountCreate": ".types",
"PublicSecretManagementDto": ".types",
"PublicSecretResponseDto": ".types",
"PublicSecretResponseDtoData": ".types",
"QueriesResponse": ".types",
"Query": ".types",
"QueryApplicationVariantsRequestOrder": ".applications",
Expand Down Expand Up @@ -1295,8 +1315,8 @@
"SecretDto": ".types",
"SecretDtoData": ".types",
"SecretKind": ".types",
"SecretResponseDto": ".types",
"SecretResponseDtoData": ".types",
"SecretManagementPolicy": ".types",
"SecretValueStatus": ".types",
"Selector": ".types",
"SessionAttachment": ".types",
"SessionAttachmentResponse": ".types",
Expand Down Expand Up @@ -1611,6 +1631,8 @@
"TriggerSubscriptionQuery": ".types",
"TriggerSubscriptionResponse": ".types",
"TriggerSubscriptionsResponse": ".types",
"UpdateSecretPayloadDto": ".types",
"UpdateSecretPayloadDtoData": ".types",
"UnprocessableEntityError": ".errors",
"UserIdsResponse": ".types",
"ValidationError": ".types",
Expand Down Expand Up @@ -1881,6 +1903,8 @@ def __dir__():
"ConfigResponseModel",
"ConnectAffordance",
"ConnectionRequirement",
"CredentialResult",
"CredentialStatus",
"CreateSimpleTestsetFromFileRequestFileType",
"CreateTestsetRevisionFromFileRequestFileType",
"CustomModelSettingsDto",
Expand All @@ -1901,6 +1925,8 @@ def __dir__():
"DiscoveredTriggerAlternative",
"DiscoveredTriggerEvent",
"DiscoveredTriggerEventType",
"DiscoveryResult",
"DiscoveryStatus",
"EditSimpleTestsetFromFileRequestFileType",
"EntityRef",
"Environment",
Expand Down Expand Up @@ -2127,8 +2153,13 @@ def __dir__():
"OrganizationUpdate",
"Permission",
"PlaygroundBuildKitContext",
"ProbeProviderResponse",
"ProjectsResponse",
"ProviderCredentials",
"PublicMountCreate",
"PublicSecretManagementDto",
"PublicSecretResponseDto",
"PublicSecretResponseDtoData",
"QueriesResponse",
"Query",
"QueryApplicationVariantsRequestOrder",
Expand Down Expand Up @@ -2174,8 +2205,8 @@ def __dir__():
"SecretDto",
"SecretDtoData",
"SecretKind",
"SecretResponseDto",
"SecretResponseDtoData",
"SecretManagementPolicy",
"SecretValueStatus",
"Selector",
"SessionAttachment",
"SessionAttachmentResponse",
Expand Down Expand Up @@ -2490,6 +2521,8 @@ def __dir__():
"TriggerSubscriptionQuery",
"TriggerSubscriptionResponse",
"TriggerSubscriptionsResponse",
"UpdateSecretPayloadDto",
"UpdateSecretPayloadDtoData",
"UnprocessableEntityError",
"UserIdsResponse",
"ValidationError",
Expand Down
Loading
Loading