Skip to content

Commit fdde915

Browse files
Proposal on how to add Azure SDK information to skills (#791)
* Add Azure SDK information to security and storage skills - Add Azure SDK package tables for Identity, Key Vault, and Storage - Add quick start code examples for all 6 languages (Python, JavaScript, C#, Java, Go, Rust) - Include installation commands for each language - Security skill: Key Vault secrets examples with identity authentication - Storage skill: Blob download examples with identity authentication * Add SDK integration tests for azure-storage and azure-security skills * Fix ESLint errors: use 'unknown' type instead of 'any' for error handling * Update plugin/skills/azure-storage/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update plugin/skills/azure-security/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update plugin/skills/azure-security/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Remove secret logging from Quick Start examples - store in variable instead * Add note explaining Rust uses DeveloperToolsCredential (no DefaultAzureCredential equivalent) * Add full Go imports to azure-storage example for consistency * Address PR review feedback: move SDK to references, add imports, fix formatting - Move SDK sections to references/sdk-usage.md for progressive disclosure - Add C# using directives to code examples - Add Java wildcard imports to reduce verbosity - Restore blank lines between MCP and CLI sections - Revert error handling to e: any for codebase consistency * chore: add eslint-disable comments for e: any pattern * chore: match existing integration test pattern (no eslint-disable) * fix: use e: unknown pattern for ESLint compliance * docs: add inline summary for SDK reference sections * Update plugin/skills/azure-storage/references/sdk-usage.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Remove SDK integration tests that don't match skill triggers The SDK content is in reference files (progressive disclosure) that are shown when the skill is already invoked. SDK-specific prompts like 'How do I use the Azure SDK...' don't reliably trigger the storage or prepare skills since their descriptions focus on service management, not SDK usage. Integration tests should test what triggers the skill, not what content is inside the skill after it's invoked. * Add SDK-related integration tests for azure-storage and azure-prepare - azure-storage: Add blob SDK usage test with prompt that triggers at 100% - azure-storage: Skip pre-existing failing storage tiers test - azure-prepare: Add Key Vault secrets integration test (100%) - azure-prepare: Add Azure Identity authentication test (100%) Test results: - azure-storage: 2 passed, 1 skipped - azure-prepare: 4 passed * Rename 'SDK Access' to 'Connection Patterns' for consistency * Skip pre-existing failing storage tiers test with better explanation The storage tiers test was already failing (0% invocation) in main, but appeared to pass because the SDK couldn't load due to missing ESM configuration. Now that ESM works, the test actually runs and reveals the prompt doesn't trigger the azure-storage skill. Restored original prompt from main and skipped until fixed. * Add access tiers to azure-storage skill description Added 'access tiers (hot, cool, archive) and lifecycle management' to the skill description to improve trigger matching for storage tier prompts. This fixes the pre-existing storage tiers integration test that was failing at 20% invocation rate (now passes at 60%). * Update SDK examples to upload, fix review issues, revert lockfile churn - Changed all SDK quick-start examples from blob download to upload (simpler) - Added missing 'import os' in Python examples (storage.md, key-vault.md) - Fixed invalid C# string interpolation in storage.md - Reverted unrelated package-lock.json peer:true changes --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 46d3634 commit fdde915

File tree

7 files changed

+394
-35
lines changed

7 files changed

+394
-35
lines changed

plugin/skills/azure-prepare/references/security.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,25 @@ Use Microsoft Defender for Cloud for:
221221

222222
---
223223

224+
## Azure Identity SDK
225+
226+
All Azure SDKs use their language's Identity library for credential-free authentication via `DefaultAzureCredential` or managed identity. Rust uses `DeveloperToolsCredential` as it doesn't have a `DefaultAzureCredential` equivalent.
227+
228+
| Language | Package | Install |
229+
|----------|---------|---------|
230+
| .NET | `Azure.Identity` | `dotnet add package Azure.Identity` |
231+
| Java | `azure-identity` | Maven: `com.azure:azure-identity` |
232+
| JavaScript | `@azure/identity` | `npm install @azure/identity` |
233+
| Python | `azure-identity` | `pip install azure-identity` |
234+
| Go | `azidentity` | `go get github.com/Azure/azure-sdk-for-go/sdk/azidentity` |
235+
| Rust | `azure_identity` | `cargo add azure_identity` |
236+
237+
For Key Vault SDK examples, see: [key-vault.md](services/key-vault.md)
238+
239+
For Storage SDK examples, see: [storage.md](services/storage.md)
240+
241+
---
242+
224243
## Further Reading
225244

226245
- [Key Vault documentation](https://learn.microsoft.com/azure/key-vault/general/overview)

plugin/skills/azure-prepare/references/services/key-vault.md

Lines changed: 76 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -117,48 +117,102 @@ secrets: [
117117
]
118118
```
119119

120-
## SDK Access
120+
## Connection Patterns
121121

122-
### Node.js
122+
### SDK Packages
123123

124-
```javascript
125-
const { SecretClient } = require("@azure/keyvault-secrets");
126-
const { DefaultAzureCredential } = require("@azure/identity");
124+
| Language | Secrets | Keys | Certificates |
125+
|----------|---------|------|--------------|
126+
| .NET | `Azure.Security.KeyVault.Secrets` | `Azure.Security.KeyVault.Keys` | `Azure.Security.KeyVault.Certificates` |
127+
| Java | `azure-security-keyvault-secrets` | `azure-security-keyvault-keys` | `azure-security-keyvault-certificates` |
128+
| JavaScript | `@azure/keyvault-secrets` | `@azure/keyvault-keys` | `@azure/keyvault-certificates` |
129+
| Python | `azure-keyvault-secrets` | `azure-keyvault-keys` | `azure-keyvault-certificates` |
130+
| Go | `azsecrets` | `azkeys` | `azcertificates` |
131+
| Rust | `azure_security_keyvault_secrets` | `azure_security_keyvault_keys` | `azure_security_keyvault_certificates` |
132+
133+
### JavaScript
127134

128-
const client = new SecretClient(
129-
process.env.KEY_VAULT_URL,
130-
new DefaultAzureCredential()
131-
);
135+
```javascript
136+
import { DefaultAzureCredential } from "@azure/identity";
137+
import { SecretClient } from "@azure/keyvault-secrets";
132138

139+
const client = new SecretClient(process.env.KEY_VAULT_URL, new DefaultAzureCredential());
133140
const secret = await client.getSecret("database-connection-string");
134-
console.log(secret.value);
141+
// Use secret.value securely - do not log secrets
135142
```
136143

137144
### Python
138145

139146
```python
147+
import os
140148
from azure.keyvault.secrets import SecretClient
141149
from azure.identity import DefaultAzureCredential
142150

143-
client = SecretClient(
144-
vault_url=os.environ["KEY_VAULT_URL"],
145-
credential=DefaultAzureCredential()
146-
)
147-
151+
client = SecretClient(vault_url=os.environ["KEY_VAULT_URL"], credential=DefaultAzureCredential())
148152
secret = client.get_secret("database-connection-string")
149-
print(secret.value)
153+
# Use secret.value securely - do not log secrets
150154
```
151155

152-
### .NET
156+
### C#
153157

154158
```csharp
155-
var client = new SecretClient(
156-
new Uri(Environment.GetEnvironmentVariable("KEY_VAULT_URL")),
157-
new DefaultAzureCredential()
158-
);
159+
using Azure.Identity;
160+
using Azure.Security.KeyVault.Secrets;
159161

162+
var client = new SecretClient(new Uri(Environment.GetEnvironmentVariable("KEY_VAULT_URL")), new DefaultAzureCredential());
160163
KeyVaultSecret secret = await client.GetSecretAsync("database-connection-string");
161-
Console.WriteLine(secret.Value);
164+
// Use secret.Value securely - do not log secrets
165+
```
166+
167+
### Java
168+
169+
```java
170+
import com.azure.identity.*;
171+
import com.azure.security.keyvault.secrets.*;
172+
import com.azure.security.keyvault.secrets.models.*;
173+
174+
SecretClient client = new SecretClientBuilder()
175+
.vaultUrl(System.getenv("KEY_VAULT_URL"))
176+
.credential(new DefaultAzureCredentialBuilder().build())
177+
.buildClient();
178+
KeyVaultSecret secret = client.getSecret("database-connection-string");
179+
// Use secret.getValue() securely - do not log secrets
180+
```
181+
182+
### Go
183+
184+
```go
185+
package main
186+
187+
import (
188+
"context"
189+
"os"
190+
191+
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
192+
"github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets"
193+
)
194+
195+
func main() {
196+
cred, _ := azidentity.NewDefaultAzureCredential(nil)
197+
client, _ := azsecrets.NewClient(os.Getenv("KEY_VAULT_URL"), cred, nil)
198+
199+
resp, _ := client.GetSecret(context.Background(), "database-connection-string", "", nil)
200+
// Use *resp.Value securely - do not log secrets
201+
}
202+
```
203+
204+
### Rust
205+
206+
Note: Rust uses `DeveloperToolsCredential` as it doesn't have a `DefaultAzureCredential` equivalent.
207+
208+
```rust
209+
use azure_identity::DeveloperToolsCredential;
210+
use azure_security_keyvault_secrets::SecretClient;
211+
212+
let credential = DeveloperToolsCredential::new(None)?;
213+
let client = SecretClient::new(std::env::var("KEY_VAULT_URL")?, credential.clone(), None)?;
214+
let secret = client.get_secret("database-connection-string", None).await?.into_model()?;
215+
// Use secret.value securely - do not log secrets
162216
```
163217

164218
## Environment Variables

plugin/skills/azure-prepare/references/services/storage.md

Lines changed: 99 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -137,35 +137,122 @@ resource fileShare 'Microsoft.Storage/storageAccounts/fileServices/shares@2023-0
137137

138138
## Connection Patterns
139139

140-
### Node.js
140+
### SDK Packages
141+
142+
| Language | Blob | Queue | File Share | Data Lake |
143+
|----------|------|-------|------------|-----------|
144+
| .NET | `Azure.Storage.Blobs` | `Azure.Storage.Queues` | `Azure.Storage.Files.Shares` | `Azure.Storage.Files.DataLake` |
145+
| Java | `azure-storage-blob` | `azure-storage-queue` | `azure-storage-file-share` | `azure-storage-file-datalake` |
146+
| JavaScript | `@azure/storage-blob` | `@azure/storage-queue` | `@azure/storage-file-share` | `@azure/storage-file-datalake` |
147+
| Python | `azure-storage-blob` | `azure-storage-queue` | `azure-storage-file-share` | `azure-storage-file-datalake` |
148+
| Go | `azblob` | `azqueue` | `azfile` | `azdatalake` |
149+
| Rust | `azure_storage_blob` | `azure_storage_queue` | - | - |
150+
151+
### JavaScript
141152

142153
```javascript
143-
const { BlobServiceClient } = require("@azure/storage-blob");
154+
import { DefaultAzureCredential } from "@azure/identity";
155+
import { BlobServiceClient } from "@azure/storage-blob";
144156

145-
const blobServiceClient = BlobServiceClient.fromConnectionString(
146-
process.env.AZURE_STORAGE_CONNECTION_STRING
157+
const client = new BlobServiceClient(
158+
`https://${process.env.AZURE_STORAGE_ACCOUNT}.blob.core.windows.net`,
159+
new DefaultAzureCredential()
147160
);
148-
const containerClient = blobServiceClient.getContainerClient("uploads");
161+
const container = client.getContainerClient("uploads");
162+
const blob = container.getBlockBlobClient("my-file.txt");
163+
await blob.uploadData(Buffer.from("Hello, Azure Storage!"));
149164
```
150165

151166
### Python
152167

153168
```python
169+
import os
170+
from azure.identity import DefaultAzureCredential
154171
from azure.storage.blob import BlobServiceClient
155172

156-
blob_service_client = BlobServiceClient.from_connection_string(
157-
os.environ["AZURE_STORAGE_CONNECTION_STRING"]
173+
service = BlobServiceClient(
174+
account_url=f"https://{os.environ['AZURE_STORAGE_ACCOUNT']}.blob.core.windows.net",
175+
credential=DefaultAzureCredential()
158176
)
159-
container_client = blob_service_client.get_container_client("uploads")
177+
container = service.get_container_client("uploads")
178+
blob = container.get_blob_client("my-file.txt")
179+
blob.upload_blob(b"Hello, Azure Storage!", overwrite=True)
160180
```
161181

162-
### .NET
182+
### C#
163183

164184
```csharp
165-
var blobServiceClient = new BlobServiceClient(
166-
Environment.GetEnvironmentVariable("AZURE_STORAGE_CONNECTION_STRING")
185+
using Azure.Identity;
186+
using Azure.Storage.Blobs;
187+
188+
var accountName = Environment.GetEnvironmentVariable("AZURE_STORAGE_ACCOUNT");
189+
var client = new BlobServiceClient(
190+
new Uri($"https://{accountName}.blob.core.windows.net"),
191+
new DefaultAzureCredential()
167192
);
168-
var containerClient = blobServiceClient.GetBlobContainerClient("uploads");
193+
var container = client.GetBlobContainerClient("uploads");
194+
var blob = container.GetBlobClient("my-file.txt");
195+
await blob.UploadAsync(BinaryData.FromString("Hello, Azure Storage!"), overwrite: true);
196+
```
197+
198+
### Java
199+
200+
```java
201+
import com.azure.identity.*;
202+
import com.azure.storage.blob.*;
203+
import com.azure.core.util.BinaryData;
204+
205+
BlobServiceClient client = new BlobServiceClientBuilder()
206+
.endpoint("https://" + System.getenv("AZURE_STORAGE_ACCOUNT") + ".blob.core.windows.net")
207+
.credential(new DefaultAzureCredentialBuilder().build())
208+
.buildClient();
209+
BlobContainerClient container = client.getBlobContainerClient("uploads");
210+
BlobClient blob = container.getBlobClient("my-file.txt");
211+
blob.upload(BinaryData.fromString("Hello, Azure Storage!"), true);
212+
```
213+
214+
### Go
215+
216+
```go
217+
package main
218+
219+
import (
220+
"context"
221+
"os"
222+
223+
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
224+
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
225+
)
226+
227+
func main() {
228+
cred, _ := azidentity.NewDefaultAzureCredential(nil)
229+
client, _ := azblob.NewClient(
230+
"https://"+os.Getenv("AZURE_STORAGE_ACCOUNT")+".blob.core.windows.net",
231+
cred, nil,
232+
)
233+
data := []byte("Hello, Azure Storage!")
234+
_, _ = client.UploadBuffer(context.Background(), "uploads", "my-file.txt", data, nil)
235+
}
236+
```
237+
238+
### Rust
239+
240+
Note: Rust uses `DeveloperToolsCredential` as it doesn't have a `DefaultAzureCredential` equivalent.
241+
242+
```rust
243+
use azure_identity::DeveloperToolsCredential;
244+
use azure_storage_blob::{BlobClient, BlobClientOptions};
245+
246+
let credential = DeveloperToolsCredential::new(None)?;
247+
let blob_client = BlobClient::new(
248+
&format!("https://{}.blob.core.windows.net/", std::env::var("AZURE_STORAGE_ACCOUNT")?),
249+
"uploads",
250+
"my-file.txt",
251+
Some(credential),
252+
Some(BlobClientOptions::default()),
253+
)?;
254+
let data = b"Hello, Azure Storage!";
255+
blob_client.upload(None, data.to_vec().into()).await?;
169256
```
170257

171258
## Managed Identity Access

plugin/skills/azure-storage/SKILL.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: azure-storage
3-
description: Azure Storage Services including Blob Storage, File Shares, Queue Storage, Table Storage, and Data Lake. Provides object storage, SMB file shares, async messaging, NoSQL key-value, and big data analytics capabilities.
3+
description: Azure Storage Services including Blob Storage, File Shares, Queue Storage, Table Storage, and Data Lake. Provides object storage, SMB file shares, async messaging, NoSQL key-value, and big data analytics capabilities. Includes access tiers (hot, cool, archive) and lifecycle management.
44
---
55

66
# Azure Storage Services
@@ -78,3 +78,7 @@ For deep documentation on specific services:
7878
- Blob storage patterns and lifecycle -> [Blob Storage documentation](https://learn.microsoft.com/azure/storage/blobs/storage-blobs-overview)
7979
- File shares and Azure File Sync -> [Azure Files documentation](https://learn.microsoft.com/azure/storage/files/storage-files-introduction)
8080
- Queue patterns and poison handling -> [Queue Storage documentation](https://learn.microsoft.com/azure/storage/queues/storage-queues-introduction)
81+
82+
## Azure SDKs
83+
84+
For building applications that interact with Azure Storage programmatically, Azure provides SDK packages in multiple languages (.NET, Java, JavaScript, Python, Go, Rust). See [SDK Usage Guide](references/sdk-usage.md) for package names, installation commands, and quick start examples.

0 commit comments

Comments
 (0)