fai-azure-blob-lifecycle — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited fai-azure-blob-lifecycle (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Creates lifecycle management policies for Azure Blob Storage that automatically tier cold blobs to cool/archive storage and delete expired data. Prevents the common setup mistake: storing everything in hot tier and manually moving objects months later — instead, automate the transition on creation date or last access time.
| Signal | Example |
|---|---|
| Storage bill is growing unbounded | All blobs remain in hot tier indefinitely |
| Manual archival process exists | Quarterly script to move "old" blobs to archive |
| Compliance requires data deletion | GDPR right-to-be-forgotten after N days |
| RAG chunk storage is expensive | 300GB of embeddings in hot tier |
from azure.storage.blob import BlobServiceClient
from azure.identity import DefaultAzureCredential
from collections import defaultdict
from datetime import datetime, timedelta
client = BlobServiceClient(
account_url=f"https://{STORAGE_ACCOUNT}.blob.core.windows.net",
credential=DefaultAzureCredential(),
)
distribution = defaultdict(int)
size_by_tier = defaultdict(lambda: {"count": 0, "bytes": 0})
for container in client.list_containers():
for blob in client.get_container_client(container.name).list_blobs():
tier = blob.blob_tier or "hot"
age_days = (datetime.utcnow() - blob.last_modified).days
distribution[tier] += 1
size_by_tier[tier]["count"] += 1
size_by_tier[tier]["bytes"] += blob.size
if age_days > 90:
print(f"{blob.name} ({tier}) — {age_days} days old, {blob.size} bytes")
print(f"\nTier distribution: {dict(distribution)}")
for tier, stats in size_by_tier.items():
mb = stats["bytes"] / 1024 / 1024
print(f" {tier}: {stats['count']} blobs, {mb:.0f} MB"){
"rules": [
{
"name": "auto-archive-raw-embeddings",
"enabled": true,
"type": "Lifecycle",
"definition": {
"actions": {
"baseBlob": {
"tierToCool": { "daysAfterModificationGreaterThan": 30 },
"tierToArchive": { "daysAfterModificationGreaterThan": 90 },
"delete": { "daysAfterModificationGreaterThan": 365 }
},
"snapshot": {
"delete": { "daysAfterCreationGreaterThan": 30 }
}
},
"filters": {
"blobTypes": ["blockBlob"],
"prefixMatch": ["documents/embeddings/"],
"blobIndexMatch": [
{
"name": "archive-eligible",
"op": "==",
"value": "true"
}
]
}
}
}
]
}param storageAccountName string
param lifecyclePolicyJson string = loadTextContent('lifecycle-policy.json')
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
name: storageAccountName
}
resource managementPolicy 'Microsoft.Storage/storageAccounts/managementPolicies@2023-01-01' = {
name: 'default'
parent: storageAccount
properties: {
policy: json(lifecyclePolicyJson)
}
}def estimate_annual_savings(
hot_gb: float,
cool_gb: float,
archive_gb: float,
region: str = "East US"
) -> dict:
# Pricing per GB/month (as of Apr 2026)
prices = {
"hot": 0.0184, # $0.0184/GB/month
"cool": 0.0099, # $0.0099/GB/month (46% savings)
"archive": 0.00099, # $0.00099/GB/month (95% savings)
}
monthly = {
"hot": hot_gb * prices["hot"],
"cool": cool_gb * prices["cool"],
"archive": archive_gb * prices["archive"],
}
# Baseline: everything in hot
baseline_monthly = (hot_gb + cool_gb + archive_gb) * prices["hot"]
return {
"monthly_cost_tiered": sum(monthly.values()),
"monthly_cost_all_hot": baseline_monthly,
"annual_savings": (baseline_monthly - sum(monthly.values())) * 12,
}
savings = estimate_annual_savings(hot_gb=100, cool_gb=200, archive_gb=500)
print(f"Annual savings: ${savings['annual_savings']:.2f}")// Azure Data Explorer / Log Analytics query
StorageBlobLogs
| where OperationName == "TransferBlobToCool" or OperationName == "TransferBlobToArchive"
| summarize
cool_transfers = countif(OperationName == "TransferBlobToCool"),
archive_transfers = countif(OperationName == "TransferBlobToArchive"),
total_bytes_moved = sum(tobigint(RequestBodyLength))
by bin(TimeGenerated, 1d)
| project
TimeGenerated,
cool_transfers,
archive_transfers,
total_bytes_moved = total_bytes_moved / 1024 / 1024 / 1024| Action | Trigger | Use Case | Cost |
|---|---|---|---|
| tierToCool | 30 days post-modification | Backup, cold analytics | 46% cheaper |
| tierToArchive | 90 days post-modification | Legal hold, compliance archive | 95% cheaper |
| delete | 365+ days old | GDPR/CCPA right-to-be-forgotten | Zero |
| Pillar | Contribution |
|---|---|
| Cost Optimization | Automatic tiering reduces storage bill by 60-70% without manual work |
| Reliability | Policy rules can be versioned in IaC; rollback by re-applying prior policy |
blobIndexMatch) for fine-grained policies without naming conventions~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.