Skip to content
Open
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
15 changes: 13 additions & 2 deletions .github/renovate.json5
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,21 @@
"customType": "regex",
"managerFilePatterns": ["/^versions\\.env$/"],
"matchStrings": [
"# renovate: datasource=(?<datasource>\\S+) depName=(?<depName>\\S+) versioning=(?<versioning>\\S+)\\s+WEAVER_VERSION=(?<currentValue>\\S+)",
"# renovate: datasource=(?<datasource>\\S+) depName=(?<depName>\\S+) packageName=(?<packageName>\\S+) versioning=(?<versioning>\\S+)\\s+SEMCONV_GENAI_REF=(?<currentValue>\\S+)"
"# renovate: datasource=(?<datasource>\\S+) depName=(?<depName>\\S+) versioning=(?<versioning>\\S+)\\s+WEAVER_VERSION=(?<currentValue>\\S+)"
]
},
{
// semantic-conventions-genai has no releases, so we track main's HEAD as
// a pinned commit. git-refs digest updates need the branch in
// currentValue and the SHA in currentDigest, so currentValue is templated
// to `main` and SEMCONV_GENAI_REF is captured as the digest.
"customType": "regex",
"managerFilePatterns": ["/^versions\\.env$/"],
"matchStrings": [
"# renovate: datasource=(?<datasource>\\S+) depName=(?<depName>\\S+) packageName=(?<packageName>\\S+)\\s+SEMCONV_GENAI_REF=(?<currentDigest>\\S+)"
],
"currentValueTemplate": "main"
},
{
// Keep .weaver.toml schema URL pinned to the latest Weaver tag.
"customType": "regex",
Expand Down
112 changes: 112 additions & 0 deletions .github/workflows/auto-conformance-policies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: Auto conformance policies

# Keeps the committed conformance policies (policies/genai_span_validation.rego
# and policies/_schemas.rego) in sync when Renovate bumps SEMCONV_GENAI_REF or
# WEAVER_VERSION in versions.env. Renovate's postUpgradeTasks only run on
# self-hosted Renovate, so we regenerate here instead and push the result back
# to the Renovate branch. Mirrors opentelemetry-java-instrumentation's
# auto-license-report workflow.
on:
push:
branches:
- 'renovate/**'
paths:
- 'versions.env'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
generate:
runs-on: ubuntu-latest
outputs:
patch: ${{ steps.create-patch.outputs.exists }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"

- name: Set up uv
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2

- name: Read pinned weaver version
id: versions
run: |
# shellcheck disable=SC2002
cat versions.env | grep -E '^WEAVER_VERSION=' >> "$GITHUB_OUTPUT"

- name: Install weaver ${{ steps.versions.outputs.WEAVER_VERSION }}
env:
WEAVER_VERSION: ${{ steps.versions.outputs.WEAVER_VERSION }}
run: |
WEAVER_ASSET="weaver-x86_64-unknown-linux-gnu"
WEAVER_URL="https://github.com/open-telemetry/weaver/releases/download/${WEAVER_VERSION}/${WEAVER_ASSET}.tar.xz"
curl -sSL "$WEAVER_URL" | tar -xJ -C /tmp "${WEAVER_ASSET}/weaver"
sudo mv "/tmp/${WEAVER_ASSET}/weaver" /usr/local/bin/weaver
weaver --version

- name: Provision semconv registry
run: |
uv sync --frozen --all-packages
uv run python -c "from opentelemetry.test_util_genai import _setup_weaver; _setup_weaver.semconv_registry()"

- name: Regenerate conformance policies
run: make generate-conformance-policies

- id: create-patch
name: Create patch file
run: |
git add -N --ignore-removal policies
git diff > patch
Comment on lines +66 to +67
if [ -s patch ]; then
echo "exists=true" >> "$GITHUB_OUTPUT"
fi

- name: Upload patch file
if: steps.create-patch.outputs.exists == 'true'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
path: patch
name: patch

# Separate job to isolate the OTELBOT private key: job `generate` runs weaver
# against freshly-fetched semconv content and never sees the push credential;
# this job runs no untrusted code, only `git apply` of the produced patch.
apply:
runs-on: ubuntu-latest
needs: generate
if: needs.generate.outputs.patch == 'true'
steps:
- name: Download patch
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: patch
path: ${{ runner.temp }}

- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: otelbot-token
with:
client-id: ${{ vars.OTELBOT_CLIENT_ID }}
private-key: ${{ secrets.OTELBOT_PRIVATE_KEY }}

- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ github.ref_name }}
token: ${{ steps.otelbot-token.outputs.token }}

- name: Configure CLA-approved git bot
run: .github/scripts/use-cla-approved-github-bot.sh
Comment on lines +104 to +105

- name: Apply patch and push
run: |
git apply "${{ runner.temp }}/patch"
git add policies
git commit -m "Regenerate conformance policies"
git push
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ opentelemetry-admin-jobs.txt
.claude/settings.local.json

# Generated by test_util_genai._setup_weaver
policies/_schemas.rego
.build/

# Conformance test weaver live-check reports
Expand Down
48 changes: 48 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0

.PHONY: generate-conformance-policies

# Cache the semconv provisioning writes to (mirrors _setup_weaver._cache_dir).
SEMCONV_CACHE ?= $(HOME)/.cache/otel-conformance/semconv
SEMCONV_GENAI_REF := $(shell sed -n 's/^SEMCONV_GENAI_REF=//p' versions.env)
REGISTRY := $(SEMCONV_CACHE)/genai-$(SEMCONV_GENAI_REF)/model

# rego-constant name -> semconv content-schema file under $(REGISTRY)/gen-ai.
# Referenced from policies/genai_content_validation.rego. Weaver resolves the
# registry with only the `json_schema:` path, not the file body, so the schemas
# are inlined here with jq instead of via the template. Fold into the template
# once weaver can emit json_schema content directly.
SCHEMAS := \
input_messages:gen-ai-input-messages.json \
output_messages:gen-ai-output-messages.json \
system_instructions:gen-ai-system-instructions.json \
tool_definitions:gen-ai-tool-definitions.json \
retrieval_documents:gen-ai-retrieval-documents.json

# Regenerate the committed policy rego from the pinned GenAI registry:
# policies/_schemas.rego semconv JSON content schemas, via jq
# Run after bumping SEMCONV_GENAI_REF in versions.env. Requires the jq binary on
# PATH and a provisioned registry — any conformance tox env fetches + filters it
# into $(SEMCONV_CACHE).
generate-conformance-policies:
@test -d "$(REGISTRY)" || { \
echo "registry not provisioned at $(REGISTRY)"; \
echo "run a conformance env first, e.g. tox -e py314-test-instrumentation-genai-openai-conformance"; \
exit 1; }
@out=policies/_schemas.rego; \
{ echo "# Auto-generated from semantic-conventions. Do not edit."; \
echo "# Regenerate with \`make generate-conformance-policies\`."; \
printf 'package live_check_advice\n\nimport rego.v1\n'; } > "$$out"; \
for pair in $(SCHEMAS); do \
key=$${pair%%:*}; src="$(REGISTRY)/gen-ai/$${pair#*:}"; \
printf '\n' >> "$$out"; \
if [ -f "$$src" ]; then \
printf '_schema_%s := ' "$$key" >> "$$out"; \
jq --indent 2 'walk(if type=="object" and .["$$ref"]=="http://json-schema.org/draft-07/schema#" then (.type="object" | del(.["$$ref"])) else . end)' "$$src" >> "$$out"; \
else \
echo "$$src not found — emitting null stub" >&2; \
printf '_schema_%s := null\n' "$$key" >> "$$out"; \
fi; \
done; \
echo "Wrote $$out"
Loading