(chore) Move backwards compatibility checks to weaver. (#1327)

Co-authored-by: Liudmila Molkova <limolkova@microsoft.com>
This commit is contained in:
Josh Suereth 2024-08-20 11:29:36 -04:00 committed by GitHub
parent 881b3f0b80
commit bad36854b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 1069 additions and 54 deletions

View File

@ -86,13 +86,6 @@ jobs:
make attribute-registry-generation
git diff --exit-code './docs/attributes-registry/*.md' || (echo 'Attribute registry markdown is out of date, please run "make attribute-registry-generation" and commit the changes in this PR.' && exit 1)
semantic-conventions-compatibility:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: verify semantic convention compatibility with latest released version
run: make compatibility-check
schemas-check:
runs-on: ubuntu-latest
steps:
@ -115,3 +108,18 @@ jobs:
- uses: actions/checkout@v1
- name: verify semantic conventions yaml definitions
run: make check-policies
polices-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: verify semantic conventions yaml definitions
run: make test-policies
# TODO: Remove this once policies-check is the only enforcement on github.
semantic-conventions-compatibility:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: verify semantic convention compatibility with latest released version
run: make compatibility-check

View File

@ -22,7 +22,11 @@ CHLOGGEN_CONFIG := .chloggen/config.yaml
# see https://github.com/open-telemetry/build-tools/releases for semconvgen updates
# Keep links in model/README.md and .vscode/settings.json in sync!
SEMCONVGEN_VERSION=0.25.0
WEAVER_VERSION=0.7.0
# see https://github.com/open-telemetry/weaver/releases for weaver updates
WEAVER_VERSION=0.8.0
OPA_POLICY_AGENT_VERSION=0.67.1
# From where to resolve the containers (e.g. "otel/weaver").
CONTAINER_REPOSITORY=docker.io
@ -111,20 +115,6 @@ install-yamllint:
yamllint:
yamllint .
# Check semantic convention policies on YAML files
.PHONY: check-policies
check-policies:
docker run --rm -v $(PWD)/model:/source -v $(PWD)/policies:/policies -v $(PWD)/templates:/templates \
otel/weaver:${WEAVER_VERSION} registry check \
--registry=/source \
--diagnostic-format=ansi \
--policy=/policies/registry.rego
# Test rego policies
.PHONY: test-policies
test-policies:
docker run --rm -v $(PWD)/policies:/policies openpolicyagent/opa:0.67.1 test --explain fails /policies
# Generate markdown tables from YAML definitions
.PHONY: table-generation
table-generation:
@ -159,26 +149,6 @@ table-check:
--dry-run \
/spec
# A previous iteration of calculating "LATEST_RELEASED_SEMCONV_VERSION"
# relied on "git describe". However, that approach does not work with
# light-weight developer forks/branches that haven't synced tags. Hence the
# more complex implementation of this using "git ls-remote".
#
# The output of "git ls-remote" looks something like this:
#
# e531541025992b68177a68b87628c5dc75c4f7d9 refs/tags/v1.21.0
# cadfe53949266d33476b15ca52c92f682600a29c refs/tags/v1.22.0
# ...
#
# .. which is why some additional processing is required to extract the
# latest version number and strip off the "v" prefix.
LATEST_RELEASED_SEMCONV_VERSION := $(shell git ls-remote --tags https://github.com/open-telemetry/semantic-conventions.git | cut -f 2 | sort --reverse | head -n 1 | tr '/' ' ' | cut -d ' ' -f 3 | $(SED) 's/v//g')
.PHONY: compatibility-check
compatibility-check:
docker run --rm -v $(PWD)/model:/source -v $(PWD)/docs:/spec --pull=always \
$(SEMCONVGEN_CONTAINER) -f /source compatibility --previous-version $(LATEST_RELEASED_SEMCONV_VERSION)
.PHONY: schema-check
schema-check:
$(TOOLS_DIR)/schema_check.sh
@ -234,11 +204,40 @@ chlog-update: $(CHLOGGEN)
generate-gh-issue-templates:
$(TOOLS_DIR)/scripts/update-issue-template-areas.sh
# A previous iteration of calculating "LATEST_RELEASED_SEMCONV_VERSION"
# relied on "git describe". However, that approach does not work with
# light-weight developer forks/branches that haven't synced tags. Hence the
# more complex implementation of this using "git ls-remote".
#
# The output of "git ls-remote" looks something like this:
#
# e531541025992b68177a68b87628c5dc75c4f7d9 refs/tags/v1.21.0
# cadfe53949266d33476b15ca52c92f682600a29c refs/tags/v1.22.0
# ...
#
# .. which is why some additional processing is required to extract the
# latest version number and strip off the "v" prefix.
LATEST_RELEASED_SEMCONV_VERSION := $(shell git ls-remote --tags https://github.com/open-telemetry/semantic-conventions.git | cut -f 2 | sort --reverse | head -n 1 | tr '/' ' ' | cut -d ' ' -f 3 | $(SED) 's/v//g')
.PHONY: check-policies
check-policies:
docker run --rm -v $(PWD)/model:/source -v $(PWD)/docs:/spec -v $(PWD)/policies:/policies \
otel/weaver:${WEAVER_VERSION} registry check \
--registry=/source \
--policy=/policies/registry.rego \
--policy=/policies/attribute_name_collisions.rego \
--policy=/policies/yaml_schema.rego
--baseline-registry=https://github.com/open-telemetry/semantic-conventions/archive/refs/tags/v$(LATEST_RELEASED_SEMCONV_VERSION).zip[model] \
--policy=/policies
# Test rego policies
.PHONY: test-policies
test-policies:
docker run --rm -v $(PWD)/policies:/policies -v $(PWD)/policies_test:/policies_test \
openpolicyagent/opa:${OPA_POLICY_AGENT_VERSION} test \
--explain fails \
/policies \
/policies_test
# TODO: This is now duplicative with weaver policy checks. We can remove
# once github action requirements are updated.
.PHONY: compatibility-check
compatibility-check:
docker run --rm -v $(PWD)/model:/source -v $(PWD)/docs:/spec --pull=always \
$(SEMCONVGEN_CONTAINER) -f /source compatibility --previous-version $(LATEST_RELEASED_SEMCONV_VERSION)

View File

@ -1,14 +1,16 @@
package after_resolution
import rego.v1
# Data structures to make checking things faster.
attribute_names := { data |
group := input.groups[_]
attr := group.attributes[_]
data := { "name": attr.name, "const_name": to_const_name(attr.name), "namespace_prefix": to_namespace_prefix(attr.name) }
attribute_names := { obj |
group := input.groups[_];
attr := group.attributes[_];
obj := { "name": attr.name, "const_name": to_const_name(attr.name), "namespace_prefix": to_namespace_prefix(attr.name) }
}
deny[attr_registry_collision(description, name)] {
deny contains attr_registry_collision(description, name) if {
some i
name := attribute_names[i].name
const_name := attribute_names[i].const_name
@ -24,7 +26,7 @@ deny[attr_registry_collision(description, name)] {
description := sprintf("Attribute '%s' has the same constant name '%s' as '%s'.", [name, const_name, collisions])
}
deny[attr_registry_collision(description, name)] {
deny contains attr_registry_collision(description, name) if {
some i
name := attribute_names[i].name
prefix := attribute_names[i].namespace_prefix
@ -39,7 +41,7 @@ deny[attr_registry_collision(description, name)] {
description := sprintf("Attribute '%s' is used as a namespace in '%s'.", [name, collisions])
}
attr_registry_collision(description, attr_name) = violation {
attr_registry_collision(description, attr_name) = violation if {
violation := {
"id": description,
"type": "semconv_attribute",
@ -49,11 +51,11 @@ attr_registry_collision(description, attr_name) = violation {
}
}
to_namespace_prefix(name) = namespace {
to_namespace_prefix(name) = namespace if {
namespace := concat("", [name, "."])
}
to_const_name(name) = const_name {
to_const_name(name) = const_name if {
const_name := replace(name, ".", "_")
}

352
policies/compatibility.rego Normal file
View File

@ -0,0 +1,352 @@
package comparison_after_resolution
import rego.v1
# Semantic Convention Registry Compatibility Checker
#
# This file contains rules for checking backward compatibility
# between different versions of semantic convention registries.
# It builds upon the data structures and rules defined in the
# semconv package.
# Import the previous release (baseline) and current sets of attributes, metrics.
baseline_attributes := [attr |
some g in data.semconv.registry_baseline_groups
some attr in g.attributes
]
registry_attributes := [attr |
some g in data.semconv.registry_groups
some attr in g.attributes
]
registry_attribute_names := {attr.name |
some g in data.semconv.registry_groups
some attr in g.attributes
}
baseline_metrics := [ g |
some g in data.semconv.baseline_groups
g.type == "metric"
]
registry_metrics := [ g |
some g in data.semconv.groups
g.type == "metric"
]
registry_metric_names := { g.metric_name | some g in registry_metrics }
# Rules we enforce:
# - Attributes
# - [x] Attributes cannot be removed
# - [x] Attributes cannot "degrade" stability (stable->experimental)
# - [x] Stable attributes cannot change type
# - Enum members
# - [x] Stable members cannot change stability
# - [x] Values cannot change
# - [x] ids cannot be removed
# - Metrics
# - [x] metrics cannot be removed
# - [x] Stable metrics cannot become unstable
# - [x] Stable Metric units cannot change
# - [x] Stable Metric instruments cannot change
# - [x] Set of required/recommended attributes must remain the same
# Rule: Detect Removed Attributes
#
# This rule checks for attributes that existed in the baseline registry
# but are no longer present in the current registry. Removing attributes
# is considered a backward compatibility violation.
#
# In other words, we do not allow the removal of an attribute once added
# to the registry. It must exist SOMEWHERE in a group, but may be deprecated.
deny contains back_comp_violation(description, group_id, attr.name) if {
# Check if an attribute from the baseline is missing in the current registry
some attr in baseline_attributes
not registry_attribute_names[attr.name]
# Generate human readable error.
group_id := data.semconv.baseline_group_ids_by_attribute[attr.name]
description := sprintf("Attribute '%s' no longer exists in the attribute registry", [attr.name])
}
# Rule: Detect Stable Attributes moving to unstable
#
# This rule checks for attributes that were stable in the baseline registry
# but are no longer stable in the current registry. Once stable, attributes
# remain forever but may be deprecated.
deny contains back_comp_violation(description, group_id, attr.name) if {
# Find stable baseline attributes in latest registry.
some attr in baseline_attributes
attr.stability == "stable"
some nattr in registry_attributes
attr.name == nattr.name
# Enforce the policy
attr.stability != nattr.stability
# Generate human readable error.
group_id := data.semconv.baseline_group_ids_by_attribute[attr.name]
description := sprintf("Attribute '%s' was stable, but has new stability marker", [attr.name])
}
# Rule: Detect Stable Attributes changing type
#
# This rule checks for attributes that were stable in the baseline registry
# but are no longer stable in the current registry. Once stable, attributes
# remain forever but may be deprecated.
deny contains back_comp_violation(description, group_id, attr.name) if {
# Find stable baseline attributes in latest registry.
some attr in baseline_attributes
attr.stability == "stable"
some nattr in registry_attributes
attr.name == nattr.name
# Enforce the policy
# TODO - deal with enum type changes, probably in enum sections
not is_enum(attr)
attr.type != nattr.type
# Generate human readable error.
group_id := data.semconv.baseline_group_ids_by_attribute[attr.name]
attr_type_string := type_string(attr)
nattr_type_string := type_string(nattr)
description := sprintf("Attribute '%s' was '%s', but has new type '%s'", [attr.name, attr_type_string, nattr_type_string])
}
# Rule: Detect Stable enum Attributes changing type
#
# This rule checks for attributes that were stable in the baseline registry
# but are no longer stable in the current registry. Once stable, attributes
# remain forever but may be deprecated.
deny contains back_comp_violation(description, group_id, attr.name) if {
# Find stable baseline attributes in latest registry.
some attr in baseline_attributes
attr.stability == "stable"
some nattr in registry_attributes
attr.name == nattr.name
# Enforce the policy
attr.type != nattr.type
is_enum(attr)
not is_enum(nattr)
# Generate human readable error.
group_id := data.semconv.baseline_group_ids_by_attribute[attr.name]
nattr_type_string := type_string(nattr)
description := sprintf("Attribute '%s' was enum, but has new type '%s'", [attr.name, nattr_type_string])
}
# Rule: Detect Stable Enum members changing stability level
#
# This rule checks for enum values that were stable in the baseline registry
# but are no longer stable in the current registry.
deny contains back_comp_violation(description, group_id, attr.name) if {
# Find data we need to enforce: Enums in baseline/current.
some attr in baseline_attributes
attr.stability == "stable"
some nattr in registry_attributes
attr.name == nattr.name
is_enum(attr)
some member in attr.type.members
some nmember in nattr.type.members
member.id == nmember.id
# Enforce the policy
member.stability == "stable"
nmember.stability != "stable"
# Generate human readable error.
group_id := data.semconv.baseline_group_ids_by_attribute[attr.name]
description := sprintf("Enum '%s' had stable member '%s', but is no longer stable", [attr.name, member.id])
}
# Rule: Enum member values cannot change
#
# This rule checks for enum values that have the same id, but values
# are different.
deny contains back_comp_violation(description, group_id, attr.name) if {
# Find data we need to enforce: Enums in baseline/current.
some attr in baseline_attributes
attr.stability == "stable"
some nattr in registry_attributes
attr.name == nattr.name
is_enum(attr)
some member in attr.type.members
some nmember in nattr.type.members
member.id == nmember.id
# Enforce the policy
member.value != nmember.value
# Generate human readable error.
group_id := data.semconv.baseline_group_ids_by_attribute[attr.name]
description := sprintf("Enum '%s' had stable value '%s', but is now '%s'", [attr.name, member.value, nmember.value])
}
# Rule: Detect Stable Enum members missing
#
# This rule checks for enum values that were stable in the baseline registry
# but are no longer have the same values in the current registry. Once stable,
# enum values remain forever but may be deprecated.
deny contains back_comp_violation(description, group_id, attr.name) if {
# Find data we need to enforce: Enums in baseline/current.
some attr in baseline_attributes
attr.stability == "stable"
some nattr in registry_attributes
attr.name == nattr.name
is_enum(attr)
current_member_ids := {member.id | some member in nattr.type.members}
# Enforce the policy
some member in attr.type.members
not current_member_ids[member.id]
# Generate human readable error.
group_id := data.semconv.baseline_group_ids_by_attribute[attr.name]
description := sprintf("Enum '%s' had member '%s', but is no longer defined", [attr.name, member.id])
}
# Rule: Detect Removed Metrics
#
# This rule checks for stable metrics that existed in the baseline registry
# but are no longer present in the current registry. Removing attributes
# is considered a backward compatibility violation.
#
# In other words, we do not allow the removal of an attribute once added
# to the registry. It must exist SOMEWHERE in a group, but may be deprecated.
deny contains back_comp_violation(description, group_id, "") if {
# Find data we need to enforce
some metric in baseline_metrics
metric.stability == "stable"
# Enforce the policy
not registry_metric_names[metric.metric_name]
# Generate human readable error.
group_id := metric.id
description := sprintf("Metric '%s' no longer exists in semantic conventions", [metric.metric_name])
}
# Rule: Stable metrics cannot become unstable
#
# This rule checks that stable metrics cannot have their stability level changed.
deny contains back_comp_violation(description, group_id, "") if {
# Find data we need to enforce
some metric in baseline_metrics
metric.stability == "stable"
some nmetric in registry_metrics
metric.metric_name = nmetric.metric_name
# Enforce the policy
nmetric.stability != "stable"
# Generate human readable error.
group_id := metric.id
description := sprintf("Metric '%s' cannot change from stable", [metric.metric_name])
}
# Rule: Stable metrics units cannot change
#
# This rule checks that stable metrics cannot change the unit type.
deny contains back_comp_violation(description, group_id, "") if {
# Find data we need to enforce
some metric in baseline_metrics
metric.stability == "stable"
some nmetric in registry_metrics
metric.metric_name = nmetric.metric_name
# Enforce the policy
nmetric.unit != metric.unit
# Generate human readable error.
group_id := metric.id
description := sprintf("Metric '%s' cannot change unit (was '%s', now: '%s')", [metric.metric_name, metric.unit, nmetric.unit])
}
# Rule: Stable Metric instruments cannot change
#
# This rule checks that stable metrics cannot change the instrument type.
deny contains back_comp_violation(description, group_id, "") if {
# Find data we need to enforce
some metric in baseline_metrics
metric.stability == "stable"
some nmetric in registry_metrics
metric.metric_name = nmetric.metric_name
# Enforce the policy
nmetric.instrument != metric.instrument
# Generate human readable error.
group_id := metric.id
description := sprintf("Metric '%s' cannot change instrument (was '%s', now: '%s')", [metric.metric_name, metric.instrument, nmetric.instrument])
}
# Rule: Stable Metric required/recommended attributes cannot change - missing
#
# This rule checks that stable metrics have stable sets of attributes.
deny contains back_comp_violation(description, group_id, "") if {
# Find data we need to enforce
some metric in baseline_metrics
metric.stability == "stable"
some nmetric in registry_metrics
metric.metric_name = nmetric.metric_name
baseline_attributes := { attr.name |
some attr in metric.attributes
not is_opt_in(attr)
}
new_attributes := { attr.name |
some attr in nmetric.attributes
not is_opt_in(attr)
}
missing_attributes := baseline_attributes - new_attributes
# Enforce the policy
count(missing_attributes) > 0
# Generate human readable error.
group_id := metric.id
description := sprintf("Metric '%s' cannot change required/recommended attributes (missing '%s')", [metric.metric_name, missing_attributes])
}
# Rule: Stable Metric required/recommended attributes cannot change - added
#
# This rule checks that stable metrics have stable sets of attributes.
deny contains back_comp_violation(description, group_id, "") if {
# Find data we need to enforce
some metric in baseline_metrics
metric.stability == "stable"
some nmetric in registry_metrics
metric.metric_name = nmetric.metric_name
baseline_attributes := { attr.name |
some attr in metric.attributes
not is_opt_in(attr)
}
new_attributes := { attr.name |
some attr in nmetric.attributes
not is_opt_in(attr)
}
added_attributes := new_attributes - baseline_attributes
# Enforce the policy
count(added_attributes) > 0
# Generate human readable error.
group_id := metric.id
description := sprintf("Metric '%s' cannot change required/recommended attributes (added '%s')", [metric.metric_name, added_attributes])
}
# Helper Function: Create Backward Compatibility Violation Object
#
# This function generates a structured violation object for each
# detected backward compatibility issue.
back_comp_violation(description, group_id, attr_id) := violation if {
violation := {
"id": description,
"type": "semconv_attribute",
"category": "backward_compatibility",
"group": group_id,
"attr": attr_id,
}
}
# Helpers for enum values and type strings
is_enum(attr) := true if count(attr.type.members) > 0
type_string(attr) := attr.type if not is_enum(attr)
type_string(attr) := "enum" if is_enum(attr)
is_opt_in(attr) := true if attr.requirement_level == "opt_in"

View File

@ -0,0 +1,654 @@
package comparison_after_resolution
import future.keywords.if
# Check that attributes cannot be removed.
test_removed_attributes if {
count(deny) > 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing"
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
count(deny) == 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing"
}]
}],
"registry_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing"
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
}
# Check that attributes cannot change stability
test_attribute_stability_change if {
count(deny) > 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
}]
}],
"registry_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "experimental",
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
count(deny) == 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
}]
}],
"registry_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
}
# Check stable attribute changing type
test_attribute_type_change if {
count(deny) > 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": "int",
}]
}],
"registry_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": "string",
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
count(deny) == 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": "string",
}]
}],
"registry_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": "string",
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
}
# Check stable attribute enum type
test_attribute_enum_type_change if {
count(deny) > 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "test",
}]
},
}]
}],
"registry_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": "string",
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
count(deny) == 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "test",
}]
},
}]
}],
"registry_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "test",
}]
},
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
}
# Check stable attribute enum members changing to nonstable
test_attribute_enum_member_stability_change if {
count(deny) > 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "test",
"stability": "stable",
}]
},
}]
}],
"registry_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "test",
"stability": "experimental",
}]
},
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
count(deny) == 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "test",
"stability": "stable",
}]
},
}]
}],
"registry_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "test",
"stability": "stable",
}]
},
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
}
# Check stable attribute enum member values changing
test_attribute_enum_member_value_change if {
count(deny) > 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "test",
"stability": "stable",
}]
},
}]
}],
"registry_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "changed",
"stability": "stable",
}]
},
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
count(deny) == 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "test",
"stability": "stable",
}]
},
}]
}],
"registry_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "test",
"stability": "stable",
}]
},
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
}
# Check stable attribute enum member values changing
test_attribute_enum_member_missing if {
count(deny) > 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "test",
"stability": "stable",
}, {
"id": "missing",
"value": "missing",
"stability": "stable",
}]
},
}]
}],
"registry_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "changed",
"stability": "stable",
}]
},
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
count(deny) == 0 with data.semconv as {
"registry_baseline_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "test",
"stability": "stable",
}, {
"id": "missing",
"value": "missing",
"stability": "stable",
}]
},
}]
}],
"registry_groups": [{
"id": "registry.test",
"type": "attribute_group",
"attributes": [{
"name": "test.missing",
"stability": "stable",
"type": {
"members": [{
"id": "test",
"value": "test",
"stability": "stable",
}, {
"id": "missing",
"value": "missing",
"stability": "stable",
}]
},
}]
}],
"baseline_group_ids_by_attribute": {
"test.missing": "registry.test"
}
}
}
# Check that metrics cannot be removed.
test_removed_metrics if {
count(deny) > 0 with data.semconv as {
"baseline_groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
}],
}
count(deny) == 0 with data.semconv as {
"baseline_groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
}],
"groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
}]
}
}
# Check that Stable metrics cannot become unstable
test_metric_stability_change if {
count(deny) > 0 with data.semconv as {
"baseline_groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
}],
"groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "experimental",
}]
}
count(deny) == 0 with data.semconv as {
"baseline_groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
}],
"groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
}]
}
}
# Check that Stable metrics cannot change unit
test_metric_unit_change if {
count(deny) > 0 with data.semconv as {
"baseline_groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "s",
}],
"groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "ms",
}]
}
count(deny) == 0 with data.semconv as {
"baseline_groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "s",
}],
"groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "s",
}]
}
}
# Check that Stable metrics cannot change unit
test_metric_instrument_change if {
count(deny) > 0 with data.semconv as {
"baseline_groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "s",
"instrument": "histogram",
}],
"groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "s",
"instrument": "gauge",
}]
}
count(deny) == 0 with data.semconv as {
"baseline_groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "s",
"instrument": "histogram",
}],
"groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "s",
"instrument": "histogram",
}]
}
}
# Check that Stable metrics cannot change required/recommended attributes
test_metric_attribute_missing if {
count(deny) > 0 with data.semconv as {
"baseline_groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "s",
"instrument": "histogram",
"attributes": [{
"name": "test.missing",
"requirement_level": "required"
}],
}],
"groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "s",
"instrument": "gauge",
}]
}
count(deny) == 0 with data.semconv as {
"baseline_groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "s",
"instrument": "histogram",
"attributes": [{
"name": "test.missing",
"requirement_level": "required"
},{
"name": "test.ignored",
"requirement_level": "opt_in"
}],
}],
"groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "s",
"instrument": "histogram",
"attributes": [{
"name": "test.missing",
"requirement_level": "required"
}],
}]
}
}
# Check that Stable metrics cannot change required/recommended attributes
test_metric_attribute_added if {
count(deny) > 0 with data.semconv as {
"baseline_groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "s",
"instrument": "histogram",
"attributes": [{
"name": "test.missing",
"requirement_level": "required"
}],
}],
"groups": [{
"id": "metric.test",
"type": "metric",
"metric_name": "test.missing",
"stability": "stable",
"unit": "s",
"instrument": "gauge",
"attributes": [{
"name": "test.missing",
"requirement_level": "required"
}, {
"name": "test.added",
"requirement_level": "required"
}],
}]
}
}