Skip to content

Introduce Async API counterparts for AE base class#3673

Open
cheenamalhotra wants to merge 4 commits into
mainfrom
dev/cheena/async-ae
Open

Introduce Async API counterparts for AE base class#3673
cheenamalhotra wants to merge 4 commits into
mainfrom
dev/cheena/async-ae

Conversation

@cheenamalhotra
Copy link
Copy Markdown
Member

For #3672:

Introduces async API counterparts in base class 'SqlColumnEncryptionKeyStoreProvider'

@cheenamalhotra cheenamalhotra added this to the 7.0-preview2 milestone Oct 8, 2025
@cheenamalhotra cheenamalhotra requested a review from a team as a code owner October 8, 2025 04:20
Copilot AI review requested due to automatic review settings October 8, 2025 04:20
@github-project-automation github-project-automation Bot moved this to To triage in SqlClient Board Oct 8, 2025
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

Adds asynchronous counterparts to key store provider APIs in SqlColumnEncryptionKeyStoreProvider to enable async implementations for Always Encrypted key operations.
Key changes:

  • Introduced async virtual methods (Decrypt/Encrypt column encryption key, Sign/Verify CMK metadata) that currently throw NotImplementedException.
  • Added corresponding XML documentation entries for the new async methods.
  • Minor wording adjustments in existing XML return documentation.

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

File Description
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlColumnEncryptionKeyStoreProvider.cs Adds async virtual method stubs for encryption key and metadata operations.
doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionKeyStoreProvider.xml Documents newly added async methods and adjusts some existing return descriptions.

Comment thread doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionKeyStoreProvider.xml Outdated
Comment thread doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionKeyStoreProvider.xml Outdated
@paulmedynski paulmedynski self-assigned this Oct 8, 2025
Copy link
Copy Markdown
Contributor

@paulmedynski paulmedynski left a comment

Choose a reason for hiding this comment

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

Asking for clarification on return types and synchronous implementation.

Copy link
Copy Markdown
Contributor

@benrr101 benrr101 left a comment

Choose a reason for hiding this comment

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

For new APIs we should have some discussion on the signatures. Definitely won't be able to get this in before preview2.

@benrr101 benrr101 modified the milestones: 7.0-preview2, 7.0.0 Oct 8, 2025
@cheenamalhotra cheenamalhotra moved this from To triage to In progress in SqlClient Board Oct 8, 2025
@cheenamalhotra cheenamalhotra moved this from In progress to In review in SqlClient Board Oct 8, 2025
@cheenamalhotra cheenamalhotra modified the milestones: 7.0.0, 7.0.0-preview3 Oct 9, 2025
paulmedynski
paulmedynski previously approved these changes Oct 10, 2025
@github-actions
Copy link
Copy Markdown

This pull request has been marked as stale due to inactivity for more than 30 days.

If you would like to keep this pull request open, please provide an update or respond to any comments. Otherwise, it will be closed automatically in 7 days.

@github-actions github-actions Bot added the Stale The Issue or PR has become stale and will be automatically closed shortly if no activity occurs. label Nov 10, 2025
@cheenamalhotra
Copy link
Copy Markdown
Member Author

Wait, wait 🙈

@github-actions github-actions Bot removed the Stale The Issue or PR has become stale and will be automatically closed shortly if no activity occurs. label Nov 11, 2025
@mdaigle mdaigle modified the milestones: 7.0.0-preview3, 7.0.0-preview4 Dec 2, 2025
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 2, 2026

This pull request has been marked as stale due to inactivity for more than 30 days.

If you would like to keep this pull request open, please provide an update or respond to any comments. Otherwise, it will be closed automatically in 7 days.

@github-actions github-actions Bot added the Stale The Issue or PR has become stale and will be automatically closed shortly if no activity occurs. label Jan 2, 2026
@cheenamalhotra
Copy link
Copy Markdown
Member Author

Stay

@github-actions github-actions Bot removed the Stale The Issue or PR has become stale and will be automatically closed shortly if no activity occurs. label Jan 3, 2026
@cheenamalhotra cheenamalhotra added the Public API 🆕 Issues/PRs that introduce new APIs to the driver. label Jan 13, 2026
@cheenamalhotra cheenamalhotra removed this from the 7.0.0-preview4 milestone Jan 20, 2026
@cheenamalhotra cheenamalhotra marked this pull request as draft May 13, 2026 20:28
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

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (2)

doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionKeyStoreProvider.xml:86

  • The new EncryptColumnEncryptionKeyAsync docs similarly omit remarks about the default fallback (sync call wrapped into a Task) and that CancellationToken isn’t observed by the default implementation. Adding this guidance would align the async docs with the existing SignColumnMasterKeyMetadataAsync remarks.
    <EncryptColumnEncryptionKeyAsync>
      <param name="masterKeyPath">
        The master key path.
      </param>
      <param name="encryptionAlgorithm">
        The encryption algorithm.
      </param>
      <param name="columnEncryptionKey">
        The plaintext column encryption key.
      </param>
      <param name="cancellationToken">
        A token to cancel the asynchronous operation.
      </param>
      <summary>
        Encrypts a column encryption key asynchronously using the column master key with the specified key path and using the specified algorithm.
      </summary>
      <returns>
        Returns a task that returns <see cref="T:System.Byte[]" /> array representing the encrypted column encryption key on completion.
      </returns>
    </EncryptColumnEncryptionKeyAsync>

doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionKeyStoreProvider.xml:173

  • VerifyColumnMasterKeyMetadataAsync includes a CancellationToken parameter, but the docs don’t explain whether/when it is observed (especially in the default implementation, which delegates to the sync method). Please document the CancellationToken semantics and default exception/faulted-task behavior for consistency with the other async members.
    <VerifyColumnMasterKeyMetadataAsync>
      <param name="masterKeyPath">
        The column master key path.
      </param>
      <param name="allowEnclaveComputations">
        Indicates whether the column master key supports enclave computations.
      </param>
      <param name="signature">
        The signature of the column master key metadata.
      </param>
      <param name="cancellationToken">
        A token to cancel the asynchronous operation.
      </param>
      <summary>
        When implemented in a derived class, this method is expected to verify the specified signature is valid for the column master key with the specified key path and the specified enclave behavior asynchronously. The default implementation returns a faulted task with <see cref="T:System.NotImplementedException" />.
      </summary>
      <returns>
        A task that, when completed, returns <see langword="true" /> if the specified signature is valid, or <see langword="false" /> if it is not valid.
      </returns>
    </VerifyColumnMasterKeyMetadataAsync>

@cheenamalhotra cheenamalhotra requested a review from benrr101 May 13, 2026 21:48
@cheenamalhotra cheenamalhotra dismissed benrr101’s stale review May 13, 2026 21:48

Updated specs as requested

@cheenamalhotra cheenamalhotra marked this pull request as ready for review May 14, 2026 16:54
Copilot AI review requested due to automatic review settings May 14, 2026 16:54
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

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

**Created**: 2026-05-13
**Status**: Draft
**Milestone**: 7.1.0-preview2

</DecryptColumnEncryptionKey>
<DecryptColumnEncryptionKeyAsync>
<param name="masterKeyPath">
The master key path.
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.

What kind of path is this expected to be? Local filesystem, UNC, URL ... ?

For example:

The local filesystem path to the master key file.  This will be used by <.NET API>; see [here] for further information.

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.

From SQL Server's perspective, masterKeyPath is an opaque provider-specific string. It's designed to uniquely identify the key material for a specific cryptographic key within the provider. For AKV, it'll be a URI; for certificates, it'll be [Store Location]/[Store Name]/[Thumbprint]. The rest of SqlClient doesn't know about its format.

The master key path.
</param>
<param name="encryptionAlgorithm">
The encryption algorithm.
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.

What kind of values are expected/accepted here? Is it an opaque string to us? Examples and where they are documented would help.

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.

It's a technically-opaque string returned by SQL Server - for the moment, it's always RSA_OAEP. This is documented here, in the algorithm_name argument.

protected SqlColumnEncryptionKeyStoreProvider() { }
/// <include file='../../../doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionKeyStoreProvider.xml' path='docs/members[@name="SqlColumnEncryptionKeyStoreProvider"]/DecryptColumnEncryptionKey/*'/>
public abstract byte[] DecryptColumnEncryptionKey(string masterKeyPath, string encryptionAlgorithm, byte[] encryptedColumnEncryptionKey);
/// <include file='../../../doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionKeyStoreProvider.xml' path='docs/members[@name="SqlColumnEncryptionKeyStoreProvider"]/DecryptColumnEncryptionKeyAsync/*'/>
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.

Let's use nullable annotation for new APIs, and then for any nullable arguments, we must document what null means.

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.

The default for CancellationToken is CancellationToken.None.

But I'd argue that all of these should follow the standard library pattern where async methods get multiple overloads. In our case, that would look like:

 public virtual System.Threading.Tasks.Task<byte[]> DecryptColumnEncryptionKeyAsync(string masterKeyPath, string encryptionAlgorithm, byte[] encryptedColumnEncryptionKey, System.Threading.CancellationToken cancellationToken)

and

 public System.Threading.Tasks.Task<byte[]> DecryptColumnEncryptionKeyAsync(string masterKeyPath, string encryptionAlgorithm, byte[] encryptedColumnEncryptionKey)

Where the second calls the first, passing CancellationToken.None.

<param name="cancellationToken">
A token to cancel the asynchronous operation.
</param>
<summary>
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.

Seems weird to put the summary after the arguments.

A token to cancel the asynchronous operation.
</param>
<summary>
Decrypts the specified encrypted value of a column encryption key asynchronously. The encrypted value is expected to be encrypted using the column master key with the specified key path and using the specified algorithm.
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.

IMO we should wrap long lines to our standard 100 chars.

The column master key path.
</param>
<param name="allowEnclaveComputations">
<see langword="true" /> to indicate that the column master key supports enclave computations; otherwise, <see langword="false" />.
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.

But what actually happens when I specify true vs false?

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.

This is handled within SQL Server. It's only used during enclave-enabled Always Encrypted, and the flag indicates that the key can be passed into the secure enclave. From the view of this part of SqlClient, it's an opaque flag which is designed to be signed.

The idea here is that SQL Server's record of the column master key is little more than metadata. This method locates the key material identified by the key path, then signs the metadata that SQL Server holds. SQL Server keeps a record of that signature, and passes it to the client for validation. It forms a trust anchor for cases where SQL Server itself is compromised, but the enclave can't be tampered with: if someone modifies the CMK's key path (to try and force the client to encrypt data with an attacker-specified key) then this validation fails. The attacker can't just recalculate the correct signature because SQL Server doesn't have access to the key material - just its metadata.

</VerifyColumnMasterKeyMetadata>
<VerifyColumnMasterKeyMetadataAsync>
<param name="masterKeyPath">
The column master key path.
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.

Same path and enclave comments.

Indicates whether the column master key supports enclave computations.
</param>
<param name="signature">
The signature of the column master key metadata.
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.

Is this expected to be a byte array returned by Sign() ? Would this accept any format/encoding signature type?

When implemented in a derived class, asynchronously digitally signs the column master key metadata with the column master key referenced by the <paramref name="masterKeyPath" /> parameter. The input values used to generate the signature should be the specified values of the <paramref name="masterKeyPath" /> and <paramref name="allowEnclaveComputations" /> parameters.
</summary>
<returns>
Returns a task that returns the signature of the column master key metadata on completion.
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.

What is the format/encoding of the signature? Is it HMAC, SHA256, etc?

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.

Strictly speaking, it's opaque. For the builtin providers' purposes, it's an RSA signature of the SHA256 hash of [Provider Name] + [Master Key Path] + [Enclave Computations Enabled]. The only real API requirement that is that an untampered signature verifies successfully, and a tampered signature does not.

}

[Fact]
public async Task DecryptColumnEncryptionKeyAsync_AcceptsCancellationToken()
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.

Should we also test that async encrypt and decrypt ignore the cancellation token?

var task = EncryptAsync(..., token);
token.Cancel();
var result = await task;
Assert.NotNull(result);

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.

It's worth noting that the default implementation of DbConnection.GetSchemaAsync will return a cancelled Task if it's passed a cancelled CancellationToken. This seems like a sensible approach to take.

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.

We should respect cancellation tokens, especially ahead of a potentially time-consuming operation.

@github-project-automation github-project-automation Bot moved this from In review to Waiting for customer in SqlClient Board May 15, 2026

Two threads may independently fetch the same key on a concurrent miss; the second write is idempotent (same decrypted value). This is acceptable and already implicitly assumed by the existing comment in `SqlSymmetricKeyCache`: "first one wins."

### Decision 8: `IMemoryCache` Has No `GetOrCreateAsync` — Use Explicit `TryGetValue`/`Set`
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.

While there's no method on IMemoryCache, there's an extension method in CacheExtensions (link). Would this be suitable?


**Rationale**: Three existing `SemaphoreSlim` sites hold their lock for the full duration of I/O:

- `SqlSymmetricKeyCache._cacheLock` — static singleton, held during `DecryptColumnEncryptionKey`
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.

This is centered on SqlSymmetricKeyCache but might be asked more broadly: do we need to retain the SemaphoreSlim instances at all?
MemoryCache is thread-safe, the documentation simply hasn't been updated yet (dotnet/AspNetCore.Docs#33103).
Post implementation, this pattern would cover:

  • checks against trusted key paths, followed by the column encryption keystore provider lookup (not thread-safe - but this wouldn't change.)
  • assignment of ColumnEncryptionKeyCacheTtl (if we say that the calls to DecryptColumnEncryptionKey/Async will no longer be serialized, we're already introducing a race condition if the provider sets that property. I'm not completely clear how serializing the assignment to the property would solve this.)
  • wrapping of the plaintext key in a SqlClientSymmetricKey instance (thread-safe.)
  • consecutive reads of static ColumnEncryptionKeyCacheTtl property (we could read this once and cache it.)
  • writing the cache (thread-safe.)

At present, the only true effect of the SemaphoreSlim is to ensure that calls to the keystore provider are serialized, and that they only occur with ColumnEncryptionKeyCacheTtl set to zero. We're explicitly removing the former constraint, and I'm not convinced we'll be able to ensure the latter in all circumstances (unless we pass it as a parameter.)

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.

Agreed


**Static Analysis (CI gate)**:

- Run a Roslyn analyzer or `grep`-based CI check to verify every `await` in `Microsoft.Data.SqlClient` and `Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider` assemblies uses `.ConfigureAwait(false)`. A single missed instance can cause production deadlocks in ASP.NET Framework / WPF / WinForms hosts. This MUST be enforced in CI, not left to manual review.
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.

We can enforce this using code quality rule CA2007.

This also impacts further consideration 1.

}

[Fact]
public async Task DecryptColumnEncryptionKeyAsync_AcceptsCancellationToken()
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.

It's worth noting that the default implementation of DbConnection.GetSchemaAsync will return a cancelled Task if it's passed a cancelled CancellationToken. This seems like a sensible approach to take.

</summary>
<returns>
Returns <see cref="T:System.Byte" />. The encrypted column encryption key.
Returns <see cref="T:System.Byte[]" /> array representing the encrypted column encryption key.
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.

Suggested change
Returns <see cref="T:System.Byte[]" /> array representing the encrypted column encryption key.
Returns a <see cref="T:System.Byte[]" /> representing the encrypted column encryption key.

</summary>
<returns>
Returns <see cref="T:System.Byte" />. The decrypted column encryption key.
Returns <see cref="T:System.Byte[]" /> array representing the decrypted column encryption key.
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.

Suggested change
Returns <see cref="T:System.Byte[]" /> array representing the decrypted column encryption key.
Returns a <see cref="T:System.Byte[]" /> representing the decrypted column encryption key.

Encrypts a column encryption key asynchronously using the column master key with the specified key path and using the specified algorithm.
</summary>
<returns>
Returns a task that returns <see cref="T:System.Byte[]" /> array representing the encrypted column encryption key on completion.
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.

Suggested change
Returns a task that returns <see cref="T:System.Byte[]" /> array representing the encrypted column encryption key on completion.
Returns a task that returns a <see cref="T:System.Byte[]" /> representing the encrypted column encryption key on completion.

Decrypts the specified encrypted value of a column encryption key asynchronously. The encrypted value is expected to be encrypted using the column master key with the specified key path and using the specified algorithm.
</summary>
<returns>
Returns a task that returns <see cref="T:System.Byte[]" /> array representing the decrypted column encryption key on completion.
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.

Suggested change
Returns a task that returns <see cref="T:System.Byte[]" /> array representing the decrypted column encryption key on completion.
Returns a task that returns a <see cref="T:System.Byte[]" /> representing the decrypted column encryption key on completion.


**Rationale**: Three existing `SemaphoreSlim` sites hold their lock for the full duration of I/O:

- `SqlSymmetricKeyCache._cacheLock` — static singleton, held during `DecryptColumnEncryptionKey`
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.

Agreed

protected SqlColumnEncryptionKeyStoreProvider() { }
/// <include file='../../../doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionKeyStoreProvider.xml' path='docs/members[@name="SqlColumnEncryptionKeyStoreProvider"]/DecryptColumnEncryptionKey/*'/>
public abstract byte[] DecryptColumnEncryptionKey(string masterKeyPath, string encryptionAlgorithm, byte[] encryptedColumnEncryptionKey);
/// <include file='../../../doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionKeyStoreProvider.xml' path='docs/members[@name="SqlColumnEncryptionKeyStoreProvider"]/DecryptColumnEncryptionKeyAsync/*'/>
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.

The default for CancellationToken is CancellationToken.None.

But I'd argue that all of these should follow the standard library pattern where async methods get multiple overloads. In our case, that would look like:

 public virtual System.Threading.Tasks.Task<byte[]> DecryptColumnEncryptionKeyAsync(string masterKeyPath, string encryptionAlgorithm, byte[] encryptedColumnEncryptionKey, System.Threading.CancellationToken cancellationToken)

and

 public System.Threading.Tasks.Task<byte[]> DecryptColumnEncryptionKeyAsync(string masterKeyPath, string encryptionAlgorithm, byte[] encryptedColumnEncryptionKey)

Where the second calls the first, passing CancellationToken.None.

}

[Fact]
public async Task DecryptColumnEncryptionKeyAsync_AcceptsCancellationToken()
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.

We should respect cancellation tokens, especially ahead of a potentially time-consuming operation.

// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
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.

These can move to UnitTests.

/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionKeyStoreProvider.xml' path='docs/members[@name="SqlColumnEncryptionKeyStoreProvider"]/DecryptColumnEncryptionKeyAsync/*'/>
public virtual Task<byte[]> DecryptColumnEncryptionKeyAsync(string masterKeyPath, string encryptionAlgorithm, byte[] encryptedColumnEncryptionKey, CancellationToken cancellationToken = default)
{
try
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.

The cancellation token should be checked and a cancelled task returned if the token is cancelled.

@benrr101 benrr101 added the Author attention needed PRs that require author to respond or make updates to PR. label May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Author attention needed PRs that require author to respond or make updates to PR. Public API 🆕 Issues/PRs that introduce new APIs to the driver.

Projects

Status: Waiting for customer

Development

Successfully merging this pull request may close these issues.

8 participants