Skip to content

[keyvault-certificates] Fix begin_create_certificate validator to accept san_ip_addresses and san_uris#46380

Open
rohitsinghal4u wants to merge 7 commits intomainfrom
fix/keyvault-certificates-san-ip-uri-validator
Open

[keyvault-certificates] Fix begin_create_certificate validator to accept san_ip_addresses and san_uris#46380
rohitsinghal4u wants to merge 7 commits intomainfrom
fix/keyvault-certificates-san-ip-uri-validator

Conversation

@rohitsinghal4u
Copy link
Copy Markdown
Contributor

Summary

Fixes a bug where CertificateClient.begin_create_certificate (and its async counterpart create_certificate) incorrectly raised ValueError when a CertificatePolicy was created with only san_ip_addresses or san_uris (with no subject, san_dns_names, san_emails, or san_user_principal_names).

IP addresses and URIs are valid Subject Alternative Name (SAN) types and should be accepted by the client's policy validator.

Root Cause

The validator in both _client.py and aio/_client.py checked:

if not (policy.san_emails or policy.san_user_principal_names or policy.san_dns_names or policy.subject):
    raise ValueError(NO_SAN_OR_SUBJECT)

san_ip_addresses and san_uris were missing from this condition.

Changes

  • azure/keyvault/certificates/_client.py — added san_ip_addresses and san_uris to the validator condition in begin_create_certificate
  • azure/keyvault/certificates/aio/_client.py — same fix for the async client's create_certificate
  • CHANGELOG.md — added 4.11.1 (Unreleased) section documenting the fix
  • tests/test_certificates_client.py — extended test_policy_expected_errors_for_create_cert to assert IP/URI-only policies no longer raise; added test_create_certificate_with_san_ip_and_uris live test (recorded)
  • tests/test_certificates_client_async.py — same test additions for the async client
  • tests/_test_case.py and tests/_async_test_case.py — fixed a secondary issue where empty-string values for AZURE_CLIENT_ID/AZURE_CLIENT_SECRET were set into the environment, causing newer versions of azure-identity's EnvironmentCredential (which checks is not None rather than truthiness) to attempt and fail ClientSecretCredential construction during developer auth. Now empty-string KEYVAULT_* vars cause the corresponding AZURE_* vars to be removed from the env, allowing DefaultAzureCredential to fall through to AzureCliCredential.
  • assets.json — updated tag to python/keyvault/azure-keyvault-certificates_a5c5c34814 (new recordings pushed)

Testing

  • Both new live tests recorded against https://kv-sdk-test-5903.vault.azure.net/
  • Both pass in playback mode
  • test_policy_expected_errors_for_create_cert (sync + async) updated and verified

@rohitsinghal4u rohitsinghal4u marked this pull request as ready for review April 17, 2026 21:04
Copilot AI review requested due to automatic review settings April 17, 2026 21:04
@rohitsinghal4u rohitsinghal4u requested a review from a team as a code owner April 17, 2026 21:04
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Key Vault Certificates client-side policy validation so SAN-only policies using IP addresses and/or URIs are accepted, and adds coverage + recordings to prevent regressions.

Changes:

  • Update sync/async certificate creation validators to treat san_ip_addresses and san_uris as satisfying the “SAN or subject required” rule.
  • Add unit assertions and new live tests (sync + async) validating IP/URI-only SAN policies; refresh test recordings/assets tag.
  • Adjust live-test credential environment-variable handling to avoid empty-string AZURE_* values interfering with DefaultAzureCredential.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
sdk/keyvault/azure-keyvault-certificates/azure/keyvault/certificates/_client.py Expands validator to include san_ip_addresses and san_uris.
sdk/keyvault/azure-keyvault-certificates/azure/keyvault/certificates/aio/_client.py Same validator expansion for async create_certificate.
sdk/keyvault/azure-keyvault-certificates/tests/test_certificates_client.py Adds sync live test + extends validator-behavior assertions.
sdk/keyvault/azure-keyvault-certificates/tests/test_certificates_client_async.py Adds async live test + extends validator-behavior assertions.
sdk/keyvault/azure-keyvault-certificates/tests/_test_case.py Avoids setting empty-string AZURE_* env vars during live tests.
sdk/keyvault/azure-keyvault-certificates/tests/_async_test_case.py Same env-var adjustment for async tests.
sdk/keyvault/azure-keyvault-certificates/CHANGELOG.md Documents the fix in 4.11.1 section.
sdk/keyvault/azure-keyvault-certificates/assets.json Updates assets tag for new recordings.
sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_models.py Changes KeyProperties.tags typing to Optional[Dict[str, str]] (appears unrelated to this PR’s stated scope).

Comment on lines +867 to +883
# san_ip_addresses alone should be accepted (no ValueError)
policy = CertificatePolicy(issuer_name=WellKnownIssuerNames.self, san_ip_addresses=["10.0.0.1"])
try:
await client.create_certificate("...", policy=policy)
except ValueError:
pytest.fail("create_certificate should not raise ValueError for san_ip_addresses-only policy")
except Exception:
pass # Expected: network/auth error since we are using a fake client

# san_uris alone should be accepted (no ValueError)
policy = CertificatePolicy(issuer_name=WellKnownIssuerNames.self, san_uris=["https://example.com"])
try:
await client.create_certificate("...", policy=policy)
except ValueError:
pytest.fail("create_certificate should not raise ValueError for san_uris-only policy")
except Exception:
pass # Expected: network/auth error since we are using a fake client
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new assertions use except Exception: pass to allow the fake client call to fail, but this will also swallow unexpected exceptions (e.g., AttributeError/TypeError from a regression in the validator or call signature) and let the test pass. Suggest catching only the expected request/auth exceptions (e.g., azure-core ServiceRequestError/ClientAuthenticationError/HttpResponseError) and letting other exceptions fail the test.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in commit e44579a. Replaced except Exception: pass with except (HttpResponseError, ServiceRequestError): pass in both test_certificates_client.py and test_certificates_client_async.py, and added HttpResponseError/ServiceRequestError to the azure.core.exceptions imports. Also removed the redundant await client.close() in the async live test (the preparer's context manager already closes the client).

Comment on lines +842 to +858
# san_ip_addresses alone should be accepted (no ValueError)
policy = CertificatePolicy(issuer_name=WellKnownIssuerNames.self, san_ip_addresses=["10.0.0.1"])
try:
client.begin_create_certificate("...", policy=policy)
except ValueError:
pytest.fail("begin_create_certificate should not raise ValueError for san_ip_addresses-only policy")
except Exception:
pass # Expected: network/auth error since we are using a fake client

# san_uris alone should be accepted (no ValueError)
policy = CertificatePolicy(issuer_name=WellKnownIssuerNames.self, san_uris=["https://example.com"])
try:
client.begin_create_certificate("...", policy=policy)
except ValueError:
pytest.fail("begin_create_certificate should not raise ValueError for san_uris-only policy")
except Exception:
pass # Expected: network/auth error since we are using a fake client
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new assertions use except Exception: pass to allow the fake client call to fail, but this will also swallow unexpected exceptions (e.g., AttributeError/TypeError from a regression in the validator or call signature) and let the test pass. Suggest catching only the expected request/auth exceptions (e.g., azure-core ServiceRequestError/ClientAuthenticationError/HttpResponseError) and letting other exceptions fail the test.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Comment on lines 254 to +259
@property
def tags(self) -> Dict[str, str]:
def tags(self) -> Optional[Dict[str, str]]:
"""Application specific metadata in the form of key-value pairs.

:returns: A dictionary of tags attached to the key.
:rtype: dict[str, str]
:rtype: dict[str, str] or None
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is scoped to azure-keyvault-certificates, but it also changes the public type signature of KeyProperties.tags in azure-keyvault-keys (now Optional[Dict[str, str]]). If this is intentional, it likely needs to be called out separately (e.g., in the PR description and/or the keys package changelog) because it affects the API surface/type-checking for a different package. If unintentional, consider reverting it from this PR.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 17, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • pypi.org
    • Triggering command: /home/REDACTED/work/azure-sdk-for-python/azure-sdk-for-python/.venv/bin/python /home/REDACTED/work/azure-sdk-for-python/azure-sdk-for-python/.venv/bin/python /home/REDACTED/work/azure-sdk-for-python/azure-sdk-for-python/.venv/lib/python3.9/site-packages/pip/__pip-REDACTED__.py install --ignore-installed --no-user --prefix /tmp/pip-build-env-6s9yafei/overlay --no-warn-script-location --no-binary :none: --only-binary :none: -i REDACTED -- setuptools>=61.0.0 wheel (dns block)
    • Triggering command: /home/REDACTED/work/azure-sdk-for-python/azure-sdk-for-python/.venv/bin/pip pip install isodate -q (dns block)
  • scanning-api.github.com
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node /home/REDACTED/work/_temp/ghcca-node/node/bin/node --enable-source-maps /home/REDACTED/work/_temp/copilot-developer-action-main/dist/index.js (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

… san_uris

- Extended the policy validator in both the sync and async CertificateClient
  to also accept policies that specify only san_ip_addresses or san_uris, which
  are valid SAN types but were previously treated as missing subject information
- Added test_create_certificate_with_san_ip_and_uris (sync + async) with live
  recordings to verify IP-only and URI-only SAN policies succeed end-to-end
- Extended test_policy_expected_errors_for_create_cert to assert that IP-only
  and URI-only policies no longer raise ValueError
- Fixed _test_case.py and _async_test_case.py to avoid setting AZURE_CLIENT_ID/
  AZURE_CLIENT_SECRET to empty strings, which newer azure-identity treats as
  an attempt to use ClientSecretCredential and raises ValueError
@rohitsinghal4u rohitsinghal4u force-pushed the fix/keyvault-certificates-san-ip-uri-validator branch from 8e9343f to db3c5f8 Compare April 18, 2026 00:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants