Ticket ID: CP-SDK-010
Fix storage key generation for SUBSCRIPTION_ONLY scope
Background
The storage key generator in the SDK uses an inconsistent format for SUBSCRIPTION_ONLY scope. This causes key conflicts between resources from different subscriptions.
Current behavior (wrong)
# SUBSCRIPTION scope currently generates:
"subscription/providers/Microsoft.Authorization/policyAssignments/my-policy"
# SUBSCRIPTION_ONLY should generate:
"sub:a1b2c3d4.../policyAssignments/my-policy"
Desired behavior
| Scope |
Storage key format |
TENANT |
tenant/{ns}/{type}/{name} |
MANAGEMENT_GROUP |
mg:{mg_id}/{type}/{name} |
SUBSCRIPTION |
sub:{sub_id}/{rg}/{type}/{name} |
SUBSCRIPTION_ONLY |
sub:{sub_id}/{type}/{name} |
RESOURCE_GROUP |
rg:{sub_id}/{rg}/{type}/{name} |
PARENT_RESOURCE |
parent:{parent_id}/{type}/{name} |
Fix
def build_storage_key(
scope: UniquenessScope,
subscription_id: str = None,
management_group_id: str = None,
resource_group: str = None,
resource_type: str = None,
resource_name: str = None,
parent_resource_id: str = None,
) -> str:
"""
Generate a unique storage key for a resource.
Use as a cache key or database primary key.
"""
match scope:
case UniquenessScope.TENANT:
return f"tenant/{resource_type}/{resource_name}"
case UniquenessScope.MANAGEMENT_GROUP:
return f"mg:{management_group_id}/{resource_type}/{resource_name}"
case UniquenessScope.SUBSCRIPTION:
rg = resource_group or "default"
return f"sub:{subscription_id}/{rg}/{resource_type}/{resource_name}"
case UniquenessScope.SUBSCRIPTION_ONLY:
# FIX: no resource group in key
return f"sub:{subscription_id}/{resource_type}/{resource_name}"
case UniquenessScope.RESOURCE_GROUP:
if not resource_group:
raise ValueError("resource_group required for RESOURCE_GROUP scope")
return f"rg:{subscription_id}/{resource_group}/{resource_type}/{resource_name}"
case UniquenessScope.PARENT_RESOURCE:
import hashlib
parent_hash = hashlib.sha256(parent_resource_id.encode()).hexdigest()[:12]
return f"parent:{parent_hash}/{resource_type}/{resource_name}"
case _:
raise ValueError(f"Unsupported scope: {scope}")
Tests
class TestBuildStorageKey:
def test_subscription_only_no_resource_group(self):
key = build_storage_key(
scope=UniquenessScope.SUBSCRIPTION_ONLY,
subscription_id="a1b2c3d4",
resource_type="policyAssignments",
resource_name="itl-foundation",
)
assert key == "sub:a1b2c3d4/policyAssignments/itl-foundation"
assert "resourceGroups" not in key
assert "None" not in key
def test_subscription_vs_subscription_only_different_keys(self):
sub_key = build_storage_key(
scope=UniquenessScope.SUBSCRIPTION,
subscription_id="a1b2",
resource_group="rg-test",
resource_type="roleAssignments",
resource_name="owner",
)
sub_only_key = build_storage_key(
scope=UniquenessScope.SUBSCRIPTION_ONLY,
subscription_id="a1b2",
resource_type="roleAssignments",
resource_name="owner",
)
assert sub_key != sub_only_key
Acceptance Criteria
Related
Ticket ID:
CP-SDK-010Fix storage key generation for SUBSCRIPTION_ONLY scope
Background
The storage key generator in the SDK uses an inconsistent format for
SUBSCRIPTION_ONLYscope. This causes key conflicts between resources from different subscriptions.Current behavior (wrong)
Desired behavior
TENANTtenant/{ns}/{type}/{name}MANAGEMENT_GROUPmg:{mg_id}/{type}/{name}SUBSCRIPTIONsub:{sub_id}/{rg}/{type}/{name}SUBSCRIPTION_ONLYsub:{sub_id}/{type}/{name}RESOURCE_GROUPrg:{sub_id}/{rg}/{type}/{name}PARENT_RESOURCEparent:{parent_id}/{type}/{name}Fix
Tests
Acceptance Criteria
SUBSCRIPTION_ONLYkey contains no resource group segmentSUBSCRIPTION_ONLYkey contains noNonestringSUBSCRIPTIONandSUBSCRIPTION_ONLYgenerate different keys for the same resourceRelated