Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .chloggen/2477.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
change_type: bug_fix
component: cloud
note: Exclude deprecated Azure members from code generation on the `cloud.platform` attribute
issues: [2477, 2455]
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"editor.rulers": [80],
"yaml.schemas": {
"https://raw.githubusercontent.com/open-telemetry/weaver/v0.15.0/schemas/semconv.schema.json": [
"https://raw.githubusercontent.com/open-telemetry/weaver/v0.16.1/schemas/semconv.schema.json": [
"model/**/*.yaml"
]
},
Expand Down
2 changes: 1 addition & 1 deletion dependencies.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Dependabot can keep this file up to date with latest containers.

# Weaver is used to generate markdown docs, and enforce policies on the model.
FROM otel/weaver:v0.15.2@sha256:b13acea09f721774daba36344861f689ac4bb8d6ecd94c4600b4d590c8fb34b9 AS weaver
FROM otel/weaver:v0.16.1@sha256:5ca4901b460217604ddb83feaca05238e2b016a226ecfb9b87a95555918a03af AS weaver

# OPA is used to test policies enforced by weaver.
FROM openpolicyagent/opa:1.5.1@sha256:7d30d984125161b7f30599c6bdf80a6f2301dbbd526725714c231aad8179e4b9 AS opa
Expand Down
21 changes: 21 additions & 0 deletions model/cloud/registry.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -180,36 +180,57 @@ groups:
brief: Azure Virtual Machines
stability: development
deprecated: "Replaced by `azure.vm`"
annotations:
code_generation:
exclude: true
- id: azure_container_apps
value: 'azure_container_apps'
brief: Azure Container Apps
stability: development
deprecated: "Replaced by `azure.container_apps`"
annotations:
code_generation:
exclude: true
- id: azure_container_instances
value: 'azure_container_instances'
brief: Azure Container Instances
stability: development
deprecated: "Replaced by `azure.container_instances`"
annotations:
code_generation:
exclude: true
- id: azure_aks
value: 'azure_aks'
brief: Azure Kubernetes Service
stability: development
deprecated: "Replaced by `azure.aks`"
annotations:
code_generation:
exclude: true
- id: azure_functions
value: 'azure_functions'
brief: Azure Functions
stability: development
deprecated: "Replaced by `azure.functions`"
annotations:
code_generation:
exclude: true
- id: azure_app_service
value: 'azure_app_service'
brief: Azure App Service
stability: development
deprecated: "Replaced by `azure.app_service`"
annotations:
code_generation:
exclude: true
- id: azure_openshift
value: 'azure_openshift'
brief: Azure Red Hat OpenShift
stability: development
deprecated: "Replaced by `azure.openshift`"
annotations:
code_generation:
exclude: true
- id: gcp_bare_metal_solution
value: 'gcp_bare_metal_solution'
brief: Google Bare Metal Solution (BMS)
Expand Down
59 changes: 59 additions & 0 deletions policies/registry.rego
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,69 @@ deny contains attr_registry_violation(description, group.id, "") if {
description := sprintf("Semconv group '%s' does not contain stability field. All semconv definitions must include stability level.", [group.id])
}

# check that member ids do not collide within the same attribute
deny contains attr_registry_violation(description, group.id, attr.id) if {
group := input.groups[_]
startswith(group.id, "registry.")

attr := group.attributes[_]
member := attr.type.members[_]

collisions := [n | n := attr.type.members[_].id; n == member.id ]
count(collisions) > 1

description := sprintf("Member with id '%s' is already defined on the attribute '%s' in the group '%s'. Member id must be unique.", [member.id, attr.id, group.id])
}

# check that member values do not collide within the same attribute
deny contains attr_registry_violation(description, group.id, attr.id) if {
group := input.groups[_]
startswith(group.id, "registry.")
attr := group.attributes[_]
member := attr.type.members[_]
not is_property_set(member, "deprecated")

collisions := [m
| m := attr.type.members[_]
not is_property_set(m, "deprecated")
m.value == member.value
]
count(collisions) > 1

description := sprintf("Member with value '%s' (id '%s') is already defined on the attribute '%s' in the group '%s'. Member value must be unique.", [member.value, member.id, attr.id, group.id])
}

# check that member const names do not collide within the same attribute
deny contains attr_registry_violation(description, group.id, attr.id) if {
group := input.groups[_]
startswith(group.id, "registry.")
attr := group.attributes[_]
member := attr.type.members[_]
not member.annotations["code_generation"]["exclude"]

const_name := to_const_name(member.id)

collisions := [m
| m := attr.type.members[_]
to_const_name(m.id) == const_name
not m.annotations["code_generation"]["exclude"]
]
count(collisions) > 1

description := sprintf("Member with const name '%s' (id '%s'), is already defined on the attribute '%s' in the group '%s'. Member const names must be unique.", [const_name, member.id, attr.id, group.id])
}

get_attribute_name(attr, group) := name if {
full_name := concat(".", [group.prefix, attr.id])

# if there was no prefix, we have a leading dot
name := trim(full_name, ".")
}

to_const_name(name) = const_name if {
const_name := replace(name, ".", "_")
}

is_property_set(obj, property) = true if {
obj[property] != null
} else = false
41 changes: 41 additions & 0 deletions policies_test/registry_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,44 @@ test_attribute_requirement_levels if {
count(before_resolution.deny) > 0 with input as {"groups": [{"id": "registry.foo", "attributes": [{"id": "foo", "requirement_level": {"recommended": "if available"}, "stability": "rc"}]}]}
count(before_resolution.deny) == 0 with input as {"groups": [{"id": "not_registry", "attributes": [{"ref": "foo", "requirement_level": "required"}]}]}
}

test_fails_on_member_id_collision if {
collision := {"groups": [
{"id": "registry.test", "prefix": "", "attributes": [{"id": "foo.bar.baz", "type": {"members": [
{"id": "member", "value": "value1", "brief": "brief", "stability": "stable"},
{"id": "member", "value": "value2", "brief": "brief", "stability": "stable"},
]}, "stability": "stable"}]},
]}
count(before_resolution.deny) == 2 with input as collision
}

test_fails_on_member_const_name_collision if {
collision := {"groups": [
{"id": "registry.test", "prefix": "", "attributes": [{"id": "foo.bar.baz", "type": {"members": [
{"id": "member_id", "value": "member_id", "brief": "brief", "stability": "stable"},
{"id": "member.id", "value": "member.id", "brief": "brief", "stability": "stable"},
]}, "stability": "stable"}]},
]}
count(before_resolution.deny) == 2 with input as collision
}

test_fails_on_member_value_collision if {
collision := {"groups": [
{"id": "registry.test", "prefix": "", "attributes": [{"id": "foo.bar.baz", "type": {"members": [
{"id": "member1", "value": "member", "brief": "brief", "stability": "stable"},
{"id": "member2", "value": "member", "brief": "brief", "stability": "stable"},
]}, "stability": "stable"}]},
]}
count(before_resolution.deny) == 2 with input as collision
}

test_passes_on_member_value_collision_with_deprecated if {
collision := {"groups": [
{"id": "registry.test", "prefix": "", "attributes": [{"id": "foo.bar.baz", "type": {"members": [
{"id": "member1", "value": "member", "brief": "brief", "stability": "stable", "deprecated": "renamed to member2"},
{"id": "member2", "value": "member", "brief": "brief", "stability": "stable"},
]}, "stability": "stable"}]},
]}
count(before_resolution.deny) == 0 with input as collision
}

Loading