diff --git a/sdk/security/keyvault/azcertificates/CHANGELOG.md b/sdk/security/keyvault/azcertificates/CHANGELOG.md index 4fd86bd00f39..d5bc2d8fcb9e 100644 --- a/sdk/security/keyvault/azcertificates/CHANGELOG.md +++ b/sdk/security/keyvault/azcertificates/CHANGELOG.md @@ -1,16 +1,14 @@ # Release History -## 1.5.0 (Unreleased) - +## 1.5.0 (2026-03-22) ### Features Added -* Added support for IP addresses and URIs in `SubjectAlternativeNames` through new `IPAddresses` and `URIs` fields - -### Breaking Changes -### Bugs Fixed +- New field `IPAddresses`, `URIs` in struct `SubjectAlternativeNames` ### Other Changes -* Upgraded to API service version `2025-07-01` + +- Upgraded to API service version `2025-07-01` + ## 1.4.0 (2025-06-12) diff --git a/sdk/security/keyvault/azcertificates/assets.json b/sdk/security/keyvault/azcertificates/assets.json index 78ad635234ca..9386bb93fd4a 100644 --- a/sdk/security/keyvault/azcertificates/assets.json +++ b/sdk/security/keyvault/azcertificates/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "go", "TagPrefix": "go/security/keyvault/azcertificates", - "Tag": "go/security/keyvault/azcertificates_d7cf8d07c6" + "Tag": "go/security/keyvault/azcertificates_a449e573ec" } diff --git a/sdk/security/keyvault/azcertificates/build.go b/sdk/security/keyvault/azcertificates/build.go deleted file mode 100644 index 1d03e9f4bb4a..000000000000 --- a/sdk/security/keyvault/azcertificates/build.go +++ /dev/null @@ -1,6 +0,0 @@ -//go:generate go run testdata/generate/transforms.go - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -package azcertificates diff --git a/sdk/security/keyvault/azcertificates/client_test.go b/sdk/security/keyvault/azcertificates/client_test.go index 5ac06692799e..0fbdd2ba3e55 100644 --- a/sdk/security/keyvault/azcertificates/client_test.go +++ b/sdk/security/keyvault/azcertificates/client_test.go @@ -735,3 +735,193 @@ func TestSubjectAlternativeNames(t *testing.T) { require.NotNil(t, getResp.Policy.X509CertificateProperties.SubjectAlternativeNames) testSerde(t, getResp.Policy.X509CertificateProperties.SubjectAlternativeNames) } + +func TestSubjectAlternativeNamesSerde(t *testing.T) { + // Test serialization round-trip with all SAN fields including IPAddresses and URIs + t.Run("AllFields", func(t *testing.T) { + san := azcertificates.SubjectAlternativeNames{ + DNSNames: []*string{to.Ptr("localhost"), to.Ptr("example.com")}, + Emails: []*string{to.Ptr("admin@example.com")}, + IPAddresses: []*string{to.Ptr("192.168.1.1"), to.Ptr("2001:0db8::1")}, + URIs: []*string{to.Ptr("https://example.com"), to.Ptr("https://test.com/path")}, + UserPrincipalNames: []*string{to.Ptr("user@domain.com")}, + } + data, err := san.MarshalJSON() + require.NoError(t, err) + + // verify JSON keys + var raw map[string]json.RawMessage + require.NoError(t, json.Unmarshal(data, &raw)) + require.Contains(t, raw, "dns_names") + require.Contains(t, raw, "emails") + require.Contains(t, raw, "ipAddresses") + require.Contains(t, raw, "uris") + require.Contains(t, raw, "upns") + + // round-trip + var san2 azcertificates.SubjectAlternativeNames + require.NoError(t, san2.UnmarshalJSON(data)) + require.Equal(t, san.DNSNames, san2.DNSNames) + require.Equal(t, san.Emails, san2.Emails) + require.Equal(t, san.IPAddresses, san2.IPAddresses) + require.Equal(t, san.URIs, san2.URIs) + require.Equal(t, san.UserPrincipalNames, san2.UserPrincipalNames) + }) + + // Test with only the new IPAddresses field + t.Run("OnlyIPAddresses", func(t *testing.T) { + san := azcertificates.SubjectAlternativeNames{ + IPAddresses: []*string{to.Ptr("10.0.0.1"), to.Ptr("fe80::1")}, + } + data, err := san.MarshalJSON() + require.NoError(t, err) + + var raw map[string]json.RawMessage + require.NoError(t, json.Unmarshal(data, &raw)) + require.Contains(t, raw, "ipAddresses") + require.NotContains(t, raw, "dns_names") + require.NotContains(t, raw, "uris") + + var san2 azcertificates.SubjectAlternativeNames + require.NoError(t, san2.UnmarshalJSON(data)) + require.Equal(t, san.IPAddresses, san2.IPAddresses) + require.Nil(t, san2.DNSNames) + require.Nil(t, san2.URIs) + }) + + // Test with only the new URIs field + t.Run("OnlyURIs", func(t *testing.T) { + san := azcertificates.SubjectAlternativeNames{ + URIs: []*string{to.Ptr("https://example.com"), to.Ptr("spiffe://cluster.local/ns/default/sa/app")}, + } + data, err := san.MarshalJSON() + require.NoError(t, err) + + var raw map[string]json.RawMessage + require.NoError(t, json.Unmarshal(data, &raw)) + require.Contains(t, raw, "uris") + require.NotContains(t, raw, "ipAddresses") + + var san2 azcertificates.SubjectAlternativeNames + require.NoError(t, san2.UnmarshalJSON(data)) + require.Equal(t, san.URIs, san2.URIs) + require.Nil(t, san2.IPAddresses) + }) + + // Test deserialization from raw JSON matching the Key Vault REST API format + t.Run("DeserializeFromJSON", func(t *testing.T) { + jsonData := []byte(`{ + "dns_names": ["host.example.com"], + "emails": ["test@example.com"], + "ipAddresses": ["192.168.0.1", "::1"], + "uris": ["https://api.example.com"], + "upns": ["admin@contoso.com"] + }`) + + var san azcertificates.SubjectAlternativeNames + require.NoError(t, san.UnmarshalJSON(jsonData)) + require.Equal(t, []*string{to.Ptr("host.example.com")}, san.DNSNames) + require.Equal(t, []*string{to.Ptr("test@example.com")}, san.Emails) + require.Equal(t, []*string{to.Ptr("192.168.0.1"), to.Ptr("::1")}, san.IPAddresses) + require.Equal(t, []*string{to.Ptr("https://api.example.com")}, san.URIs) + require.Equal(t, []*string{to.Ptr("admin@contoso.com")}, san.UserPrincipalNames) + }) + + // Test that empty SANs produce an empty JSON object + t.Run("EmptySAN", func(t *testing.T) { + san := azcertificates.SubjectAlternativeNames{} + data, err := san.MarshalJSON() + require.NoError(t, err) + require.Equal(t, "{}", string(data)) + + var san2 azcertificates.SubjectAlternativeNames + require.NoError(t, san2.UnmarshalJSON(data)) + require.Nil(t, san2.IPAddresses) + require.Nil(t, san2.URIs) + }) + + // Test complete CreateCertificateParameters serde with new SAN fields + t.Run("CreateParamsWithSANs", func(t *testing.T) { + params := azcertificates.CreateCertificateParameters{ + CertificatePolicy: &azcertificates.CertificatePolicy{ + IssuerParameters: &azcertificates.IssuerParameters{Name: to.Ptr("Self")}, + X509CertificateProperties: &azcertificates.X509CertificateProperties{ + Subject: to.Ptr("CN=TestSAN"), + SubjectAlternativeNames: &azcertificates.SubjectAlternativeNames{ + DNSNames: []*string{to.Ptr("localhost")}, + IPAddresses: []*string{to.Ptr("127.0.0.1"), to.Ptr("::1")}, + URIs: []*string{to.Ptr("https://localhost:8443")}, + }, + }, + }, + } + testSerde(t, ¶ms) + }) +} + +func TestSubjectAlternativeNamesFakeServer(t *testing.T) { + // Test using the fake server to verify SANs round-trip through create and get policy + expectedSANs := &azcertificates.SubjectAlternativeNames{ + DNSNames: []*string{to.Ptr("example.com")}, + Emails: []*string{to.Ptr("admin@example.com")}, + IPAddresses: []*string{to.Ptr("10.0.0.1"), to.Ptr("2001:db8::1")}, + URIs: []*string{to.Ptr("https://example.com/api")}, + UserPrincipalNames: []*string{to.Ptr("user@example.com")}, + } + + srv, close := mock.NewServer(mock.WithTransformAllRequestsToTestServerUrl()) + defer close() + + // Mock CreateCertificate response + srv.AppendResponse(mock.WithStatusCode(http.StatusAccepted), mock.WithBody([]byte(`{ + "id": "https://fake-vault.vault.azure.net/certificates/test-san/pending", + "status": "completed" + }`))) + + // Mock GetCertificatePolicy response with all SAN fields + srv.AppendResponse(mock.WithStatusCode(http.StatusOK), mock.WithBody([]byte(`{ + "id": "https://fake-vault.vault.azure.net/certificates/test-san/policy", + "issuer": {"name": "Self"}, + "x509_props": { + "subject": "CN=TestSAN", + "sans": { + "dns_names": ["example.com"], + "emails": ["admin@example.com"], + "ipAddresses": ["10.0.0.1", "2001:db8::1"], + "uris": ["https://example.com/api"], + "upns": ["user@example.com"] + } + } + }`))) + + client, err := azcertificates.NewClient("https://fake-vault.vault.azure.net", &azcred.Fake{}, &azcertificates.ClientOptions{ + ClientOptions: azcore.ClientOptions{Transport: srv}, + }) + require.NoError(t, err) + + // Create certificate with SANs + createParams := azcertificates.CreateCertificateParameters{ + CertificatePolicy: &azcertificates.CertificatePolicy{ + IssuerParameters: &azcertificates.IssuerParameters{Name: to.Ptr("Self")}, + X509CertificateProperties: &azcertificates.X509CertificateProperties{ + Subject: to.Ptr("CN=TestSAN"), + SubjectAlternativeNames: expectedSANs, + }, + }, + } + _, err = client.CreateCertificate(context.Background(), "test-san", createParams, nil) + require.NoError(t, err) + + // Get policy and verify SANs are deserialized correctly + policyResp, err := client.GetCertificatePolicy(context.Background(), "test-san", nil) + require.NoError(t, err) + require.NotNil(t, policyResp.X509CertificateProperties) + require.NotNil(t, policyResp.X509CertificateProperties.SubjectAlternativeNames) + + sans := policyResp.X509CertificateProperties.SubjectAlternativeNames + require.Equal(t, expectedSANs.DNSNames, sans.DNSNames) + require.Equal(t, expectedSANs.Emails, sans.Emails) + require.Equal(t, expectedSANs.IPAddresses, sans.IPAddresses) + require.Equal(t, expectedSANs.URIs, sans.URIs) + require.Equal(t, expectedSANs.UserPrincipalNames, sans.UserPrincipalNames) +} diff --git a/sdk/security/keyvault/azcertificates/go.mod b/sdk/security/keyvault/azcertificates/go.mod index fbc2331baa7e..023216c1e464 100644 --- a/sdk/security/keyvault/azcertificates/go.mod +++ b/sdk/security/keyvault/azcertificates/go.mod @@ -3,7 +3,7 @@ module github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates go 1.24.0 require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 @@ -18,9 +18,9 @@ require ( github.com/kylelemons/godebug v1.1.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/crypto v0.45.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/crypto v0.47.0 // indirect + golang.org/x/net v0.49.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/text v0.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/sdk/security/keyvault/azcertificates/go.sum b/sdk/security/keyvault/azcertificates/go.sum index 30fd724fac88..22c9592961bf 100644 --- a/sdk/security/keyvault/azcertificates/go.sum +++ b/sdk/security/keyvault/azcertificates/go.sum @@ -1,5 +1,5 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16APJ7jurfbY5jnfXpJoRMc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= @@ -34,15 +34,15 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/sdk/security/keyvault/azcertificates/models_serde.go b/sdk/security/keyvault/azcertificates/models_serde.go index 9576bff6e829..e91c205b9355 100644 --- a/sdk/security/keyvault/azcertificates/models_serde.go +++ b/sdk/security/keyvault/azcertificates/models_serde.go @@ -9,7 +9,9 @@ import ( "fmt" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/datetime" "reflect" + "time" ) // MarshalJSON implements the json.Marshaller interface for type AdministratorContact. @@ -156,13 +158,13 @@ func (c *Certificate) UnmarshalJSON(data []byte) error { // MarshalJSON implements the json.Marshaller interface for type CertificateAttributes. func (c CertificateAttributes) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) - populateTimeUnix(objectMap, "created", c.Created) + populateTime[datetime.Unix](objectMap, "created", c.Created) populate(objectMap, "enabled", c.Enabled) - populateTimeUnix(objectMap, "exp", c.Expires) - populateTimeUnix(objectMap, "nbf", c.NotBefore) + populateTime[datetime.Unix](objectMap, "exp", c.Expires) + populateTime[datetime.Unix](objectMap, "nbf", c.NotBefore) populate(objectMap, "recoverableDays", c.RecoverableDays) populate(objectMap, "recoveryLevel", c.RecoveryLevel) - populateTimeUnix(objectMap, "updated", c.Updated) + populateTime[datetime.Unix](objectMap, "updated", c.Updated) return json.Marshal(objectMap) } @@ -176,16 +178,16 @@ func (c *CertificateAttributes) UnmarshalJSON(data []byte) error { var err error switch key { case "created": - err = unpopulateTimeUnix(val, "Created", &c.Created) + err = unpopulateTime[datetime.Unix](val, "Created", &c.Created) delete(rawMsg, key) case "enabled": err = unpopulate(val, "Enabled", &c.Enabled) delete(rawMsg, key) case "exp": - err = unpopulateTimeUnix(val, "Expires", &c.Expires) + err = unpopulateTime[datetime.Unix](val, "Expires", &c.Expires) delete(rawMsg, key) case "nbf": - err = unpopulateTimeUnix(val, "NotBefore", &c.NotBefore) + err = unpopulateTime[datetime.Unix](val, "NotBefore", &c.NotBefore) delete(rawMsg, key) case "recoverableDays": err = unpopulate(val, "RecoverableDays", &c.RecoverableDays) @@ -194,7 +196,7 @@ func (c *CertificateAttributes) UnmarshalJSON(data []byte) error { err = unpopulate(val, "RecoveryLevel", &c.RecoveryLevel) delete(rawMsg, key) case "updated": - err = unpopulateTimeUnix(val, "Updated", &c.Updated) + err = unpopulateTime[datetime.Unix](val, "Updated", &c.Updated) delete(rawMsg, key) } if err != nil { @@ -509,14 +511,14 @@ func (d DeletedCertificate) MarshalJSON() ([]byte, error) { return runtime.EncodeByteArray(d.CER, runtime.Base64StdFormat) }) populate(objectMap, "contentType", d.ContentType) - populateTimeUnix(objectMap, "deletedDate", d.DeletedDate) + populateTime[datetime.Unix](objectMap, "deletedDate", d.DeletedDate) populate(objectMap, "id", d.ID) populate(objectMap, "kid", d.KID) populate(objectMap, "policy", d.Policy) populate(objectMap, "preserveCertOrder", d.PreserveCertOrder) populate(objectMap, "recoveryId", d.RecoveryID) populate(objectMap, "sid", d.SID) - populateTimeUnix(objectMap, "scheduledPurgeDate", d.ScheduledPurgeDate) + populateTime[datetime.Unix](objectMap, "scheduledPurgeDate", d.ScheduledPurgeDate) populate(objectMap, "tags", d.Tags) populateByteArray(objectMap, "x5t", d.X509Thumbprint, func() any { return runtime.EncodeByteArray(d.X509Thumbprint, runtime.Base64URLFormat) @@ -545,7 +547,7 @@ func (d *DeletedCertificate) UnmarshalJSON(data []byte) error { err = unpopulate(val, "ContentType", &d.ContentType) delete(rawMsg, key) case "deletedDate": - err = unpopulateTimeUnix(val, "DeletedDate", &d.DeletedDate) + err = unpopulateTime[datetime.Unix](val, "DeletedDate", &d.DeletedDate) delete(rawMsg, key) case "id": err = unpopulate(val, "ID", &d.ID) @@ -566,7 +568,7 @@ func (d *DeletedCertificate) UnmarshalJSON(data []byte) error { err = unpopulate(val, "SID", &d.SID) delete(rawMsg, key) case "scheduledPurgeDate": - err = unpopulateTimeUnix(val, "ScheduledPurgeDate", &d.ScheduledPurgeDate) + err = unpopulateTime[datetime.Unix](val, "ScheduledPurgeDate", &d.ScheduledPurgeDate) delete(rawMsg, key) case "tags": err = unpopulate(val, "Tags", &d.Tags) @@ -588,10 +590,10 @@ func (d *DeletedCertificate) UnmarshalJSON(data []byte) error { func (d DeletedCertificateProperties) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) populate(objectMap, "attributes", d.Attributes) - populateTimeUnix(objectMap, "deletedDate", d.DeletedDate) + populateTime[datetime.Unix](objectMap, "deletedDate", d.DeletedDate) populate(objectMap, "id", d.ID) populate(objectMap, "recoveryId", d.RecoveryID) - populateTimeUnix(objectMap, "scheduledPurgeDate", d.ScheduledPurgeDate) + populateTime[datetime.Unix](objectMap, "scheduledPurgeDate", d.ScheduledPurgeDate) populate(objectMap, "tags", d.Tags) populateByteArray(objectMap, "x5t", d.X509Thumbprint, func() any { return runtime.EncodeByteArray(d.X509Thumbprint, runtime.Base64URLFormat) @@ -612,7 +614,7 @@ func (d *DeletedCertificateProperties) UnmarshalJSON(data []byte) error { err = unpopulate(val, "Attributes", &d.Attributes) delete(rawMsg, key) case "deletedDate": - err = unpopulateTimeUnix(val, "DeletedDate", &d.DeletedDate) + err = unpopulateTime[datetime.Unix](val, "DeletedDate", &d.DeletedDate) delete(rawMsg, key) case "id": err = unpopulate(val, "ID", &d.ID) @@ -621,7 +623,7 @@ func (d *DeletedCertificateProperties) UnmarshalJSON(data []byte) error { err = unpopulate(val, "RecoveryID", &d.RecoveryID) delete(rawMsg, key) case "scheduledPurgeDate": - err = unpopulateTimeUnix(val, "ScheduledPurgeDate", &d.ScheduledPurgeDate) + err = unpopulateTime[datetime.Unix](val, "ScheduledPurgeDate", &d.ScheduledPurgeDate) delete(rawMsg, key) case "tags": err = unpopulate(val, "Tags", &d.Tags) @@ -763,9 +765,9 @@ func (i *Issuer) UnmarshalJSON(data []byte) error { // MarshalJSON implements the json.Marshaller interface for type IssuerAttributes. func (i IssuerAttributes) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) - populateTimeUnix(objectMap, "created", i.Created) + populateTime[datetime.Unix](objectMap, "created", i.Created) populate(objectMap, "enabled", i.Enabled) - populateTimeUnix(objectMap, "updated", i.Updated) + populateTime[datetime.Unix](objectMap, "updated", i.Updated) return json.Marshal(objectMap) } @@ -779,13 +781,13 @@ func (i *IssuerAttributes) UnmarshalJSON(data []byte) error { var err error switch key { case "created": - err = unpopulateTimeUnix(val, "Created", &i.Created) + err = unpopulateTime[datetime.Unix](val, "Created", &i.Created) delete(rawMsg, key) case "enabled": err = unpopulate(val, "Enabled", &i.Enabled) delete(rawMsg, key) case "updated": - err = unpopulateTimeUnix(val, "Updated", &i.Updated) + err = unpopulateTime[datetime.Unix](val, "Updated", &i.Updated) delete(rawMsg, key) } if err != nil { @@ -1428,6 +1430,17 @@ func populate(m map[string]any, k string, v any) { } } +func populateTime[T dateTimeConstraints](m map[string]any, k string, t *time.Time) { + if t == nil { + return + } else if azcore.IsNullValue(t) { + m[k] = nil + } else if !reflect.ValueOf(t).IsNil() { + newTime := T(*t) + m[k] = (*T)(&newTime) + } +} + func populateByteArray[T any](m map[string]any, k string, b []T, convert func() any) { if azcore.IsNullValue(b) { m[k] = nil @@ -1447,3 +1460,20 @@ func unpopulate(data json.RawMessage, fn string, v any) error { } return nil } + +func unpopulateTime[T dateTimeConstraints](data json.RawMessage, fn string, t **time.Time) error { + if data == nil || string(data) == "null" { + return nil + } + var aux T + if err := json.Unmarshal(data, &aux); err != nil { + return fmt.Errorf("struct field %s: %v", fn, err) + } + newTime := time.Time(aux) + *t = &newTime + return nil +} + +type dateTimeConstraints interface { + datetime.PlainDate | datetime.PlainTime | datetime.RFC1123 | datetime.RFC3339 | datetime.Unix +} diff --git a/sdk/security/keyvault/azcertificates/testdata/_metadata.json b/sdk/security/keyvault/azcertificates/testdata/_metadata.json index 2df4d87535b7..30deb12a788c 100644 --- a/sdk/security/keyvault/azcertificates/testdata/_metadata.json +++ b/sdk/security/keyvault/azcertificates/testdata/_metadata.json @@ -1,4 +1,6 @@ { - "apiVersion": "2025-07-01", - "emitterVersion": "0.8.2" -} \ No newline at end of file + "apiVersions": { + "KeyVault": "2025-07-01" + }, + "emitterVersion": "0.10.2" +} diff --git a/sdk/security/keyvault/azcertificates/testdata/perf/go.mod b/sdk/security/keyvault/azcertificates/testdata/perf/go.mod index 750996e8991b..1c9f013f16ae 100644 --- a/sdk/security/keyvault/azcertificates/testdata/perf/go.mod +++ b/sdk/security/keyvault/azcertificates/testdata/perf/go.mod @@ -5,7 +5,7 @@ go 1.24.0 replace github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates => ../.. require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.4.0 @@ -18,8 +18,8 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect - golang.org/x/crypto v0.45.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/crypto v0.47.0 // indirect + golang.org/x/net v0.49.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/text v0.33.0 // indirect ) diff --git a/sdk/security/keyvault/azcertificates/testdata/perf/go.sum b/sdk/security/keyvault/azcertificates/testdata/perf/go.sum index 4026c253f53b..6dbf1ff5ad49 100644 --- a/sdk/security/keyvault/azcertificates/testdata/perf/go.sum +++ b/sdk/security/keyvault/azcertificates/testdata/perf/go.sum @@ -1,5 +1,5 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16APJ7jurfbY5jnfXpJoRMc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= @@ -28,14 +28,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/sdk/security/keyvault/azcertificates/time_unix.go b/sdk/security/keyvault/azcertificates/time_unix.go deleted file mode 100644 index a9698ee84f6e..000000000000 --- a/sdk/security/keyvault/azcertificates/time_unix.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// Code generated by Microsoft (R) Go Code Generator. DO NOT EDIT. - -package azcertificates - -import ( - "encoding/json" - "fmt" - "github.com/Azure/azure-sdk-for-go/sdk/azcore" - "reflect" - "time" -) - -type timeUnix time.Time - -func (t timeUnix) MarshalJSON() ([]byte, error) { - return json.Marshal(time.Time(t).Unix()) -} - -func (t *timeUnix) UnmarshalJSON(data []byte) error { - var seconds int64 - if err := json.Unmarshal(data, &seconds); err != nil { - return err - } - *t = timeUnix(time.Unix(seconds, 0)) - return nil -} - -func (t timeUnix) String() string { - return fmt.Sprintf("%d", time.Time(t).Unix()) -} - -func populateTimeUnix(m map[string]any, k string, t *time.Time) { - if t == nil { - return - } else if azcore.IsNullValue(t) { - m[k] = nil - return - } else if reflect.ValueOf(t).IsNil() { - return - } - m[k] = (*timeUnix)(t) -} - -func unpopulateTimeUnix(data json.RawMessage, fn string, t **time.Time) error { - if data == nil || string(data) == "null" { - return nil - } - var aux timeUnix - if err := json.Unmarshal(data, &aux); err != nil { - return fmt.Errorf("struct field %s: %v", fn, err) - } - *t = (*time.Time)(&aux) - return nil -} diff --git a/sdk/security/keyvault/azcertificates/tsp-location.yaml b/sdk/security/keyvault/azcertificates/tsp-location.yaml index b6ceafea8bfe..c963cfed439e 100644 --- a/sdk/security/keyvault/azcertificates/tsp-location.yaml +++ b/sdk/security/keyvault/azcertificates/tsp-location.yaml @@ -1,5 +1,5 @@ -directory: specification/keyvault/Security.KeyVault.Certificates -commit: 6733bfe4447e09f501d691efb69b4045dd536f8d +directory: specification/keyvault/data-plane/Certificates +commit: 06d1c57f16f9da0b2672c34e2066aa0a35b6e62c repo: Azure/azure-rest-api-specs -additionalDirectories: -- specification/keyvault/Security.KeyVault.Common +additionalDirectories: +- specification/keyvault/data-plane/Certificates/common