use crate::packs::{DestructivePattern, Pack, SafePattern};
use crate::{destructive_pattern, safe_pattern};
#[must_use]
pub fn create_pack() -> Pack {
Pack {
id: "cloud.azure".to_string(),
name: "Azure CLI",
description: "Protects against destructive Azure CLI operations like vm delete, \
storage account delete, and resource group delete",
keywords: &["az", "delete", "vm", "storage", "acr", "registry"],
safe_patterns: create_safe_patterns(),
destructive_patterns: create_destructive_patterns(),
keyword_matcher: None,
safe_regex_set: None,
safe_regex_set_is_complete: false,
}
}
fn create_safe_patterns() -> Vec<SafePattern> {
vec![
safe_pattern!("az-show", r"az\s+\S+\s+show"),
safe_pattern!("az-list", r"az\s+\S+\s+list"),
safe_pattern!("az-account", r"az\s+account"),
safe_pattern!("az-configure", r"az\s+configure"),
safe_pattern!("az-login", r"az\s+login"),
safe_pattern!("az-version", r"az\s+version"),
safe_pattern!("az-help", r"az\s+.*--help"),
safe_pattern!("az-what-if", r"az\s+.*--what-if"),
]
}
#[allow(clippy::too_many_lines)]
fn create_destructive_patterns() -> Vec<DestructivePattern> {
vec![
destructive_pattern!(
"vm-delete",
r"az\s+vm\s+delete",
"az vm delete permanently destroys virtual machines.",
Critical,
"vm delete permanently destroys Azure VMs:\n\n\
- VM is deallocated and deleted\n\
- OS disk deleted (unless --os-disk=detach)\n\
- Data disks detached but not deleted\n\
- Public IP released\n\n\
Preserve disks: az vm delete --os-disk detach --data-disks detach"
),
destructive_pattern!(
"storage-delete",
r"az\s+storage\s+account\s+delete",
"az storage account delete permanently destroys the storage account and all data.",
Critical,
"storage account delete destroys entire storage account:\n\n\
- ALL blobs, files, queues, tables deleted\n\
- All containers and their contents gone\n\
- Cannot be recovered without backups\n\n\
List contents first: az storage container list --account-name NAME"
),
destructive_pattern!(
"blob-delete",
r"az\s+storage\s+(?:blob|container)\s+delete",
"az storage blob/container delete permanently removes data.",
High,
"storage blob/container delete removes data:\n\n\
- Blob delete removes individual blobs\n\
- Container delete removes container and ALL blobs\n\
- Soft delete may allow recovery if enabled\n\n\
Check soft delete: az storage account show --name NAME --query blobServiceProperties"
),
destructive_pattern!(
"sql-delete",
r"az\s+sql\s+(?:server|db)\s+delete",
"az sql server/db delete permanently destroys the database.",
Critical,
"sql server/db delete destroys databases:\n\n\
- Server delete removes ALL databases on server\n\
- Database delete removes specific database\n\
- Point-in-time restore possible within retention period\n\n\
Create backup: az sql db export --name DB --server SRV --storage-uri URI"
),
destructive_pattern!(
"group-delete",
r"az\s+group\s+delete",
"az group delete removes the entire resource group and ALL resources within it!",
Critical,
"group delete removes ENTIRE resource group:\n\n\
- ALL resources in the group deleted\n\
- VMs, storage, databases, networks - everything\n\
- Cannot be undone\n\
- --no-wait returns immediately (deletion continues)\n\n\
This is one of the most destructive Azure commands!"
),
destructive_pattern!(
"aks-delete",
r"az\s+aks\s+delete",
"az aks delete removes the entire AKS cluster.",
Critical,
"aks delete removes the entire Kubernetes cluster:\n\n\
- All nodes and workloads terminated\n\
- Persistent volumes may be deleted\n\
- Load balancers and IPs released\n\
- Node resource group also deleted\n\n\
Backup workloads: kubectl get all -A -o yaml > backup.yaml"
),
destructive_pattern!(
"webapp-delete",
r"az\s+webapp\s+delete",
"az webapp delete removes the App Service.",
High,
"webapp delete removes App Service:\n\n\
- Application code and configuration deleted\n\
- Custom domain mappings removed\n\
- SSL certificates may be deleted\n\
- Deployment slots also deleted\n\n\
Backup config: az webapp config show --name NAME -g RG"
),
destructive_pattern!(
"functionapp-delete",
r"az\s+functionapp\s+delete",
"az functionapp delete removes the Azure Function App.",
High,
"functionapp delete removes Azure Functions:\n\n\
- All functions and configuration deleted\n\
- Triggers and bindings removed\n\
- Function keys lost\n\
- Associated storage may be affected\n\n\
Export functions if not in version control."
),
destructive_pattern!(
"cosmosdb-delete",
r"az\s+cosmosdb\s+(?:delete|database\s+delete|collection\s+delete)",
"az cosmosdb delete permanently destroys the Cosmos DB resource.",
Critical,
"cosmosdb delete destroys Cosmos DB resources:\n\n\
- Account delete removes entire Cosmos DB account\n\
- Database delete removes database and all containers\n\
- Collection delete removes container and data\n\n\
Enable point-in-time restore for recovery options."
),
destructive_pattern!(
"keyvault-delete",
r"az\s+keyvault\s+delete",
"az keyvault delete removes the Key Vault. Secrets may be unrecoverable.",
Critical,
"keyvault delete removes Key Vault:\n\n\
- All secrets, keys, certificates deleted\n\
- Soft delete allows recovery (if enabled)\n\
- Purge protection prevents permanent deletion\n\
- Vault name reserved for recovery period\n\n\
Check protection: az keyvault show --name NAME --query properties.enablePurgeProtection"
),
destructive_pattern!(
"vnet-delete",
r"az\s+network\s+vnet\s+delete",
"az network vnet delete removes the virtual network.",
High,
"network vnet delete removes virtual network:\n\n\
- Network must be empty (no subnets in use)\n\
- Connected resources lose connectivity\n\
- Peerings to other VNets broken\n\
- Network security groups may remain\n\n\
Check usage: az network vnet subnet list --vnet-name VNET -g RG"
),
destructive_pattern!(
"acr-delete",
r"az\s+acr\s+delete",
"az acr delete removes the container registry and all images.",
Critical,
"acr delete removes entire container registry:\n\n\
- ALL repositories and images deleted\n\
- All tags and manifests gone\n\
- Webhooks and replications removed\n\
- Registry name becomes available to others\n\n\
List repos: az acr repository list --name REGISTRY"
),
destructive_pattern!(
"acr-repository-delete",
r"az\s+acr\s+repository\s+delete",
"az acr repository delete permanently deletes the repository and its images.",
High,
"acr repository delete removes repository:\n\n\
- All tags and images in repository deleted\n\
- Running containers unaffected (cached)\n\
- New pulls will fail\n\n\
List tags: az acr repository show-tags --name REG --repository REPO"
),
destructive_pattern!(
"acr-repository-untag",
r"az\s+acr\s+repository\s+untag",
"az acr repository untag removes tags from images.",
Medium,
"acr repository untag removes image tags:\n\n\
- Tag removed from manifest\n\
- Image still exists if other tags reference it\n\
- Untagged images may be garbage collected\n\n\
Lower risk: manifests can be re-tagged if digest known."
),
]
}
#[cfg(test)]
mod tests {
use super::*;
use crate::packs::test_helpers::*;
#[test]
fn acr_patterns_block() {
let pack = create_pack();
assert_blocks(&pack, "az acr delete --name myregistry", "acr delete");
assert_blocks(
&pack,
"az acr repository delete --name myregistry --image repo:tag",
"repository delete",
);
assert_blocks(
&pack,
"az acr repository untag --name myregistry --image repo:tag",
"repository untag",
);
}
}