mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
* feat: add Azure Policy alias normalization/denormalization Add normalizer and denormalizer for ARM JSON resources, enabling Azure Policy alias short names to become direct paths into a flat structure. - Normalizer: flattens properties wrappers, lowercases keys, resolves per-alias versioned ARM paths, handles sub-resource array flattening, element-level field remaps, and array base renames - Denormalizer: reverses all transformations with casing restoration - AliasRegistry: loads production alias catalogs and data policy manifests - Types: serde deserialization for ARM provider alias formats - YAML test suite: 13 test files covering normalize, denormalize, round-trip, data-plane, edge cases, malformed input, sub-resources, and registry API - Benchmark suite for normalization performance * feat: add FFI and C# bindings for alias normalization - FFI: alias_registry.rs with C-compatible API for loading catalogs, normalizing resources, and denormalizing back to ARM JSON - C#: AliasRegistry wrapper class with NativeMethods P/Invoke bindings and integration tests - Updated Cargo.lock files for new serde_json dependency
450 lines
13 KiB
YAML
450 lines
13 KiB
YAML
aliases_json: |
|
|
[
|
|
{
|
|
"namespace": "Microsoft.Storage",
|
|
"resourceTypes": [
|
|
{
|
|
"resourceType": "storageAccounts",
|
|
"aliases": [
|
|
{
|
|
"name": "Microsoft.Storage/storageAccounts/supportsHttpsTrafficOnly",
|
|
"defaultPath": "properties.supportsHttpsTrafficOnly",
|
|
"paths": []
|
|
},
|
|
{
|
|
"name": "Microsoft.Storage/storageAccounts/isHnsEnabled",
|
|
"defaultPath": "properties.isHnsEnabled",
|
|
"paths": []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"namespace": "Microsoft.Network",
|
|
"resourceTypes": [
|
|
{
|
|
"resourceType": "networkSecurityGroups",
|
|
"aliases": [
|
|
{
|
|
"name": "Microsoft.Network/networkSecurityGroups/securityRules[*].protocol",
|
|
"defaultPath": "properties.securityRules[*].properties.protocol",
|
|
"paths": []
|
|
},
|
|
{
|
|
"name": "Microsoft.Network/networkSecurityGroups/securityRules[*].access",
|
|
"defaultPath": "properties.securityRules[*].properties.access",
|
|
"paths": []
|
|
},
|
|
{
|
|
"name": "Microsoft.Network/networkSecurityGroups/securityRules[*].name",
|
|
"defaultPath": "properties.securityRules[*].name",
|
|
"paths": []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
|
|
cases:
|
|
- note: round-trip simple resource
|
|
input:
|
|
name: myStorage
|
|
type: "Microsoft.Storage/storageAccounts"
|
|
location: westus2
|
|
sku:
|
|
name: Standard_LRS
|
|
properties:
|
|
supportsHttpsTrafficOnly: true
|
|
isHnsEnabled: false
|
|
round_trip: true
|
|
expected_round_trip:
|
|
name: myStorage
|
|
type: "Microsoft.Storage/storageAccounts"
|
|
location: westus2
|
|
sku:
|
|
name: Standard_LRS
|
|
properties:
|
|
supportsHttpsTrafficOnly: true
|
|
isHnsEnabled: false
|
|
|
|
- note: round-trip sub-resource
|
|
input:
|
|
name: myNsg
|
|
type: "Microsoft.Network/networkSecurityGroups"
|
|
properties:
|
|
securityRules:
|
|
- name: rule1
|
|
properties:
|
|
protocol: Tcp
|
|
access: Allow
|
|
round_trip: true
|
|
expected_round_trip:
|
|
name: myNsg
|
|
type: "Microsoft.Network/networkSecurityGroups"
|
|
properties:
|
|
securityRules:
|
|
- name: rule1
|
|
properties:
|
|
protocol: Tcp
|
|
access: Allow
|
|
|
|
- note: round-trip versioned array alias (element field remap)
|
|
aliases_json: |
|
|
[
|
|
{
|
|
"namespace": "Microsoft.Network",
|
|
"resourceTypes": [
|
|
{
|
|
"resourceType": "firewallPolicies",
|
|
"aliases": [
|
|
{
|
|
"name": "Microsoft.Network/firewallPolicies/rules[*].priority",
|
|
"defaultPath": "properties.rules[*].properties.priority",
|
|
"paths": [
|
|
{
|
|
"path": "properties.rules[*].properties.prio",
|
|
"apiVersions": ["2021-01-01"]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "Microsoft.Network/firewallPolicies/rules[*].name",
|
|
"defaultPath": "properties.rules[*].name",
|
|
"paths": []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
input:
|
|
name: myPolicy
|
|
type: "Microsoft.Network/firewallPolicies"
|
|
properties:
|
|
rules:
|
|
- name: rule1
|
|
properties:
|
|
prio: 100
|
|
api_version: "2021-01-01"
|
|
round_trip: true
|
|
expected_round_trip:
|
|
name: myPolicy
|
|
type: "Microsoft.Network/firewallPolicies"
|
|
properties:
|
|
rules:
|
|
- name: rule1
|
|
properties:
|
|
prio: 100
|
|
|
|
# Regression: default and versioned paths both produce exactly one element
|
|
# remap (same count), but the source field differs. A length-only comparison
|
|
# would silently reuse the default aggregate, producing incorrect results for
|
|
# the versioned API version.
|
|
- note: round-trip versioned remap with same count but different source field
|
|
aliases_json: |
|
|
[
|
|
{
|
|
"namespace": "Microsoft.Network",
|
|
"resourceTypes": [
|
|
{
|
|
"resourceType": "firewallPolicies",
|
|
"aliases": [
|
|
{
|
|
"name": "Microsoft.Network/firewallPolicies/rules[*].priority",
|
|
"defaultPath": "properties.rules[*].properties.oldA",
|
|
"paths": [
|
|
{
|
|
"path": "properties.rules[*].properties.oldB",
|
|
"apiVersions": ["2023-06-01"]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "Microsoft.Network/firewallPolicies/rules[*].name",
|
|
"defaultPath": "properties.rules[*].name",
|
|
"paths": []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
input:
|
|
name: myPolicy
|
|
type: "Microsoft.Network/firewallPolicies"
|
|
properties:
|
|
rules:
|
|
- name: rule1
|
|
properties:
|
|
oldB: 100
|
|
api_version: "2023-06-01"
|
|
round_trip: true
|
|
expected_round_trip:
|
|
name: myPolicy
|
|
type: "Microsoft.Network/firewallPolicies"
|
|
properties:
|
|
rules:
|
|
- name: rule1
|
|
properties:
|
|
oldB: 100
|
|
|
|
- note: round-trip systemData and extendedLocation
|
|
input:
|
|
name: myStorage
|
|
type: "Microsoft.Storage/storageAccounts"
|
|
location: westus2
|
|
identity:
|
|
type: SystemAssigned
|
|
principalId: pid-123
|
|
userAssignedIdentities:
|
|
/subscriptions/Sub/resourceGroups/Rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/Uai1: {}
|
|
systemData:
|
|
createdBy: user@example.com
|
|
createdByType: User
|
|
createdAt: "2023-01-01T00:00:00Z"
|
|
extendedLocation:
|
|
name: edge-site-1
|
|
type: EdgeZone
|
|
properties:
|
|
supportsHttpsTrafficOnly: true
|
|
expected_normalized:
|
|
name: myStorage
|
|
type: "Microsoft.Storage/storageAccounts"
|
|
location: westus2
|
|
identity:
|
|
type: SystemAssigned
|
|
principalid: pid-123
|
|
userassignedidentities:
|
|
/subscriptions/Sub/resourceGroups/Rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/Uai1: {}
|
|
systemdata:
|
|
createdby: user@example.com
|
|
createdbytype: User
|
|
createdat: "2023-01-01T00:00:00Z"
|
|
extendedlocation:
|
|
name: edge-site-1
|
|
type: EdgeZone
|
|
supportshttpstrafficonly: true
|
|
round_trip: true
|
|
expected_round_trip:
|
|
name: myStorage
|
|
type: "Microsoft.Storage/storageAccounts"
|
|
location: westus2
|
|
identity:
|
|
type: SystemAssigned
|
|
principalId: pid-123
|
|
userAssignedIdentities:
|
|
/subscriptions/Sub/resourceGroups/Rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/Uai1: {}
|
|
systemData:
|
|
createdBy: user@example.com
|
|
createdByType: User
|
|
createdAt: "2023-01-01T00:00:00Z"
|
|
extendedLocation:
|
|
name: edge-site-1
|
|
type: EdgeZone
|
|
properties:
|
|
supportsHttpsTrafficOnly: true
|
|
|
|
# Regression: element remap must remove the stale ARM source field from the
|
|
# normalized output. Without cleanup, both the alias short name AND the
|
|
# original ARM leaf key survive; casing restoration during denormalization
|
|
# then produces a duplicate key (e.g. both "prio" and "priority").
|
|
- note: element remap removes stale ARM source field
|
|
aliases_json: |
|
|
[
|
|
{
|
|
"namespace": "Microsoft.Network",
|
|
"resourceTypes": [
|
|
{
|
|
"resourceType": "firewallPolicies",
|
|
"aliases": [
|
|
{
|
|
"name": "Microsoft.Network/firewallPolicies/rules[*].priority",
|
|
"defaultPath": "properties.rules[*].properties.prio",
|
|
"paths": []
|
|
},
|
|
{
|
|
"name": "Microsoft.Network/firewallPolicies/rules[*].name",
|
|
"defaultPath": "properties.rules[*].name",
|
|
"paths": []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
input:
|
|
name: myPolicy
|
|
type: "Microsoft.Network/firewallPolicies"
|
|
properties:
|
|
rules:
|
|
- name: rule1
|
|
properties:
|
|
prio: 42
|
|
# Normalize: "prio" (ARM leaf) → "priority" (alias short name).
|
|
# The stale "prio" key must be removed from the normalized element.
|
|
expected_normalized:
|
|
name: myPolicy
|
|
type: "Microsoft.Network/firewallPolicies"
|
|
rules:
|
|
- name: rule1
|
|
priority: 42
|
|
# Round-trip: normalize → denormalize should restore ARM structure.
|
|
round_trip: true
|
|
expected_round_trip:
|
|
name: myPolicy
|
|
type: "Microsoft.Network/firewallPolicies"
|
|
properties:
|
|
rules:
|
|
- name: rule1
|
|
properties:
|
|
prio: 42
|
|
|
|
# Regression: same stale-field-cleanup scenario but with a dotted ARM leaf
|
|
# path (e.g. "config.value" rather than a single segment "prio").
|
|
# The remove_element_field helper must navigate to the parent object and
|
|
# remove the leaf key via remove_at_dotted_path.
|
|
- note: element remap removes stale dotted ARM source field
|
|
aliases_json: |
|
|
[
|
|
{
|
|
"namespace": "Microsoft.Test",
|
|
"resourceTypes": [
|
|
{
|
|
"resourceType": "widgets",
|
|
"aliases": [
|
|
{
|
|
"name": "Microsoft.Test/widgets/items[*].rating",
|
|
"defaultPath": "properties.items[*].properties.config.score",
|
|
"paths": []
|
|
},
|
|
{
|
|
"name": "Microsoft.Test/widgets/items[*].name",
|
|
"defaultPath": "properties.items[*].name",
|
|
"paths": []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
input:
|
|
type: "Microsoft.Test/widgets"
|
|
properties:
|
|
items:
|
|
- name: w1
|
|
properties:
|
|
config:
|
|
score: 5
|
|
# Normalize: "config.score" (dotted ARM leaf) → "rating" (alias short name).
|
|
# The stale "config.score" path must be removed; only "rating" should remain.
|
|
expected_normalized:
|
|
type: "Microsoft.Test/widgets"
|
|
items:
|
|
- name: w1
|
|
config: {}
|
|
rating: 5
|
|
# Round-trip: normalize → denormalize should restore ARM structure.
|
|
round_trip: true
|
|
expected_round_trip:
|
|
type: "Microsoft.Test/widgets"
|
|
properties:
|
|
items:
|
|
- name: w1
|
|
properties:
|
|
config:
|
|
score: 5
|
|
|
|
# Regression: array base rename must move (not clone) the value so that
|
|
# the stale ARM base key does not survive in the normalized output.
|
|
# Without the removal, denormalization produces a duplicate key.
|
|
- note: array base rename removes stale ARM base key
|
|
aliases_json: |
|
|
[
|
|
{
|
|
"namespace": "Microsoft.Test",
|
|
"resourceTypes": [
|
|
{
|
|
"resourceType": "widgets",
|
|
"aliases": [
|
|
{
|
|
"name": "Microsoft.Test/widgets/items[*].label",
|
|
"defaultPath": "properties.entries[*].label",
|
|
"paths": []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
input:
|
|
type: "Microsoft.Test/widgets"
|
|
properties:
|
|
entries:
|
|
- label: hello
|
|
# Normalize: ARM base "entries" → alias base "items".
|
|
# The stale "entries" key must be removed; only "items" should remain.
|
|
expected_normalized:
|
|
type: "Microsoft.Test/widgets"
|
|
items:
|
|
- label: hello
|
|
# Round-trip: normalize → denormalize should restore ARM structure.
|
|
round_trip: true
|
|
expected_round_trip:
|
|
type: "Microsoft.Test/widgets"
|
|
properties:
|
|
entries:
|
|
- label: hello
|
|
|
|
# Regression: denormalize reverse element remap with a dotted ARM target
|
|
# must preserve restored casing (e.g. "Config.Score") rather than
|
|
# re-lowercasing it.
|
|
- note: round-trip dotted element remap preserves ARM casing
|
|
aliases_json: |
|
|
[
|
|
{
|
|
"namespace": "Microsoft.Test",
|
|
"resourceTypes": [
|
|
{
|
|
"resourceType": "widgets",
|
|
"aliases": [
|
|
{
|
|
"name": "Microsoft.Test/widgets/items[*].rating",
|
|
"defaultPath": "properties.items[*].properties.Config.Score",
|
|
"paths": []
|
|
},
|
|
{
|
|
"name": "Microsoft.Test/widgets/items[*].name",
|
|
"defaultPath": "properties.items[*].name",
|
|
"paths": []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
input:
|
|
type: "Microsoft.Test/widgets"
|
|
properties:
|
|
items:
|
|
- name: w1
|
|
properties:
|
|
Config:
|
|
Score: 9
|
|
expected_normalized:
|
|
type: "Microsoft.Test/widgets"
|
|
items:
|
|
- name: w1
|
|
config: {}
|
|
rating: 9
|
|
round_trip: true
|
|
expected_round_trip:
|
|
type: "Microsoft.Test/widgets"
|
|
properties:
|
|
items:
|
|
- name: w1
|
|
properties:
|
|
Config:
|
|
Score: 9
|