This is an automated email from the ASF dual-hosted git repository.
zqr10159 pushed a commit to branch 2.0.0
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/2.0.0 by this push:
new 0514e50d4c fix(ci): restore managed OTel runtime and release checks
0514e50d4c is described below
commit 0514e50d4c2355ac0970af851926db9c6162e9ed
Author: Logic <[email protected]>
AuthorDate: Fri Oct 9 21:48:13 2026 +0800
fix(ci): restore managed OTel runtime and release checks
Restore the runtime inputs consumed by the retained Java supervisor and
Collector release profiles. Select Go 1.26.9 and align the required transport
and OTel SDK dependencies while preserving the Collector components and
security gates.
Remove duplicate backend concurrency, validate Maven release profile
tokens, and replace the denied Markdown action with its pinned CLI version.
Validated locally: five-platform runtime builds and reproducibility,
vulnerability/license/release-asset gates, 51 focused Python tests, and 2,271
Markdown files. Remote Actions and full JVM/native/container execution remain
unverified; x/crypto retains a module-only OpenPGP advisory.
---
.github/workflows/backend-build-test.yml | 4 -
.github/workflows/doc-build-test.yml | 5 +-
hertzbeat-otel-runtime/.gitignore | 1 +
hertzbeat-otel-runtime/Makefile | 66 ++++++++
hertzbeat-otel-runtime/README.md | 176 +++++++++++++++++++++
hertzbeat-otel-runtime/builder-config.yaml | 54 +++++++
.../config/collector-config.test.yaml | 128 +++++++++++++++
hertzbeat-otel-runtime/go.mod | 8 +
hertzbeat-otel-runtime/runtime-manifest.json | 9 ++
script/ci/find_maven_release_command.py | 78 +++++++++
script/ci/test_find_maven_release_command.py | 64 ++++++++
script/ci/verify-otel-runtime-layout.sh | 14 +-
script/ci/verify-server-release-layout.sh | 2 +-
13 files changed, 597 insertions(+), 12 deletions(-)
diff --git a/.github/workflows/backend-build-test.yml
b/.github/workflows/backend-build-test.yml
index 9f2291135e..fc5561fb38 100644
--- a/.github/workflows/backend-build-test.yml
+++ b/.github/workflows/backend-build-test.yml
@@ -23,10 +23,6 @@ name: Backend CI
permissions:
contents: read
-concurrency:
- group: backend-ci-${{ github.workflow }}-${{ github.ref }}
- cancel-in-progress: true
-
on:
push:
branches: [ master, dev, action*, '2.*' ]
diff --git a/.github/workflows/doc-build-test.yml
b/.github/workflows/doc-build-test.yml
index d9fb63ce6f..bb2146cd88 100644
--- a/.github/workflows/doc-build-test.yml
+++ b/.github/workflows/doc-build-test.yml
@@ -49,9 +49,8 @@ jobs:
python-version: '3.8'
- name: Check Markdown
- uses:
DavidAnson/markdownlint-cli2-action@992badcdf24e3b8eb7e87ff9287fe931bcb00c6e
- with:
- globs: './home/**/*.md'
+ # Preserve the pinned CLI version, repository config and lint scope.
+ run: npm exec --yes [email protected] --
markdownlint-cli2 './home/**/*.md'
- name: Check filenames
run: python ./script/ci/docs/check_file_name.py
./script/ci/docs/check_file_name.json
diff --git a/hertzbeat-otel-runtime/.gitignore
b/hertzbeat-otel-runtime/.gitignore
new file mode 100644
index 0000000000..69fa449dd9
--- /dev/null
+++ b/hertzbeat-otel-runtime/.gitignore
@@ -0,0 +1 @@
+_build/
diff --git a/hertzbeat-otel-runtime/Makefile b/hertzbeat-otel-runtime/Makefile
new file mode 100644
index 0000000000..182581673c
--- /dev/null
+++ b/hertzbeat-otel-runtime/Makefile
@@ -0,0 +1,66 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0.
+
+# Use the same patched toolchain locally and in setup-go's go-version-file.
+GO_VERSION := $(shell sed -n 's/^go //p' go.mod)
+export GOTOOLCHAIN := go$(GO_VERSION)
+
+OCB_VERSION ?= v0.156.0
+RUNTIME_BINARY := _build/otelcol-hertzbeat/hertzbeat-otel-runtime
+RUNTIME_SOURCE := _build/otelcol-hertzbeat
+TEST_CONFIG := config/collector-config.test.yaml
+PLATFORMS := macos-arm64 macos-amd64 linux-arm64 linux-amd64 windows-amd64
+GO_BUILD_TAGS := remove_all_sd
+GO_LDFLAGS := -s -w
+# go-licenses does not recognize this module's shortened Apache-2.0 text, so
the
+# license target verifies the upstream file explicitly before excluding it.
+GO_FQDN_MODULE := github.com/Showmax/go-fqdn
+
+.PHONY: build build-platforms clean license-check release-assets validate
+
+build:
+ mkdir -p _build
+ go run go.opentelemetry.io/collector/cmd/builder@$(OCB_VERSION)
--config builder-config.yaml
+
+build-platforms: build
+ mkdir -p $(addprefix dist/,$(PLATFORMS))
+ cd $(RUNTIME_SOURCE) && CGO_ENABLED=0 GOOS=darwin GOARCH=arm64
GOFLAGS="-tags=$(GO_BUILD_TAGS)" go build -trimpath -ldflags="$(GO_LDFLAGS)" \
+ -o ../../dist/macos-arm64/hertzbeat-otel-runtime .
+ cd $(RUNTIME_SOURCE) && CGO_ENABLED=0 GOOS=darwin GOARCH=amd64
GOFLAGS="-tags=$(GO_BUILD_TAGS)" go build -trimpath -ldflags="$(GO_LDFLAGS)" \
+ -o ../../dist/macos-amd64/hertzbeat-otel-runtime .
+ cd $(RUNTIME_SOURCE) && CGO_ENABLED=0 GOOS=linux GOARCH=arm64
GOFLAGS="-tags=$(GO_BUILD_TAGS)" go build -trimpath -ldflags="$(GO_LDFLAGS)" \
+ -o ../../dist/linux-arm64/hertzbeat-otel-runtime .
+ cd $(RUNTIME_SOURCE) && CGO_ENABLED=0 GOOS=linux GOARCH=amd64
GOFLAGS="-tags=$(GO_BUILD_TAGS)" go build -trimpath -ldflags="$(GO_LDFLAGS)" \
+ -o ../../dist/linux-amd64/hertzbeat-otel-runtime .
+ cd $(RUNTIME_SOURCE) && CGO_ENABLED=0 GOOS=windows GOARCH=amd64
GOFLAGS="-tags=$(GO_BUILD_TAGS)" go build -trimpath -ldflags="$(GO_LDFLAGS)" \
+ -o ../../dist/windows-amd64/hertzbeat-otel-runtime.exe .
+ for platform in $(PLATFORMS); do cp runtime-manifest.json
dist/$$platform/; done
+
+license-check: build
+ cd $(RUNTIME_SOURCE) && fqdn_dir=$$(go list -m -f '{{.Dir}}'
$(GO_FQDN_MODULE)) && \
+ test -f "$$fqdn_dir/LICENSE" && \
+ grep -Fq 'Licensed under the Apache License, Version 2.0'
"$$fqdn_dir/LICENSE"
+ cd $(RUNTIME_SOURCE) && GOFLAGS="-tags=$(GO_BUILD_TAGS)" \
+ go run github.com/google/go-licenses/[email protected] check . \
+ --ignore github.com/apache/hertzbeat \
+ --ignore $(GO_FQDN_MODULE)
+
+release-assets: build-platforms
+ ../script/ci/generate-hybrid-collector-release-assets.sh
+
+validate: build
+ mkdir -p _build/validation-storage
+ touch _build/validation.log
+ HERTZBEAT_COLLECTOR_ID=phase0-test \
+ HERTZBEAT_WORKSPACE_ID=default \
+ HERTZBEAT_OTLP_HTTP_ENDPOINT=http://127.0.0.1:1157/api/otlp \
+ HERTZBEAT_OTLP_TOKEN=phase0-test-token \
+ HERTZBEAT_OTEL_HEALTH_PORT=13133 \
+ HERTZBEAT_OTEL_TEST_LOG=$$(pwd)/_build/validation.log \
+ HERTZBEAT_OTEL_FILE_STORAGE_DIR=$$(pwd)/_build/validation-storage \
+ $(RUNTIME_BINARY) validate --config $(TEST_CONFIG)
+
+clean:
+ rm -rf _build dist
diff --git a/hertzbeat-otel-runtime/README.md b/hertzbeat-otel-runtime/README.md
new file mode 100644
index 0000000000..4f5a5af286
--- /dev/null
+++ b/hertzbeat-otel-runtime/README.md
@@ -0,0 +1,176 @@
+# HertzBeat Managed Telemetry Runtime
+
+This module builds the private OpenTelemetry data-plane process supervised by
+the Java HertzBeat Collector. It is not a second HertzBeat Collector and must
+not register a separate Collector identity.
+
+The managed runtime contains host metrics, explicitly managed Prometheus
+targets, locally approved file-log profiles with persistent offsets, memory
+protection, resource detection, fixed attribute governance, batching, direct
+OTLP/HTTP export, and a loopback health endpoint.
+The Java process owns configuration, validation, lifecycle, recovery, and the
+single Collector identity. The Go process exports telemetry directly to the
+HertzBeat Server and never proxies data through Java.
+
+## Data acquisition model
+
+The runtime combines active collection with standard OTLP ingestion:
+
+- `hostmetrics`, `prometheus`, and `filelog` actively collect host metrics,
+ scrape endpoints, and approved local log files.
+- The upstream OTLP receiver accepts application metrics, logs, and traces over
+ loopback gRPC `4317` and HTTP `4318` by default.
+
+All signals share the same bounded processors and direct exporter. Applications
+still need an OpenTelemetry SDK or agent to create traces. Bundled automatic
+instrumentation is a separate capability and is not represented as telemetry
+created by the Collector itself.
+
+Resource precedence is fixed and shared by all three signals. Incoming SDK or
+receiver attributes are preserved, enabled detectors fill missing values, and
+HertzBeat ownership fields are then applied authoritatively. Authentication
+headers, tokens, cookies, and API keys are removed from resource and signal
+attributes before batching. The default detectors are only `env` and `system`;
+Docker and cloud metadata detectors run only when the typed desired
+configuration explicitly enables them. Filtering is limited to product-owned
+presets such as health-check traces, and the server cannot send raw OTTL.
+
+The direct exporter uses a bounded 2,048-request persistent queue with four
+consumers. Failed deliveries back off without an elapsed-time cutoff, and
queued
+data resumes from the owner-only file-storage directory after a runtime
restart.
+When the queue or storage is full, new input is rejected instead of growing
+memory or disk usage without a bound.
+
+## Build and validate
+
+Go 1.26.9 is pinned in `go.mod`. The Makefile selects that toolchain for
+OCB, cross-platform binaries and release checks; Go can download its verified
+toolchain if it is not cached. GitHub Actions uses the same `go-version-file`.
+The OCB/component release stays at 0.156.0; reviewed dependency overrides in
+`builder-config.yaml` carry the SDK and transport security fixes.
+
+```shell
+make validate
+make build-platforms
+make license-check
+make release-assets
+../script/ci/verify-otel-runtime-package-layout.sh
+```
+
+Generated sources, binaries, and release archives remain local under `_build`,
+`dist`, and the repository-level `dist` directory. They must not be committed.
+`release-assets` creates a per-platform CycloneDX SBOM, SHA-512 checksums, and
+the collected dependency license notices next to each Go runtime. It also runs
+the pinned license and source-call-graph vulnerability gates.
+
+## Java supervisor configuration
+
+The runtime is opt-in until the server-side managed credential handoff is
+available. A packaged Collector can enable it with these environment values:
+
+```shell
+export HERTZBEAT_OTEL_RUNTIME_ENABLED=true
+export HERTZBEAT_OTLP_HTTP_ENDPOINT=http://server:1157/api/otlp
+export HERTZBEAT_OTLP_TOKEN=<managed-intake-token>
+export HERTZBEAT_WORKSPACE_ID=default
+```
+
+`IDENTITY` remains the only HertzBeat Collector identity. The Java supervisor
+resolves the matching binary from `runtime/<os>-<arch>`, writes a generated
+configuration without credentials, validates it, waits for loopback health,
+and then reports its own runtime state. A runtime failure degrades only this
+optional data plane; Java agentless collection continues.
+
+### OTLP Agent and Gateway modes
+
+Agent mode is the default. It listens only on `127.0.0.1:4317` and
+`127.0.0.1:4318`, caps each request at 4 MiB, and is intended for applications
+running on the same host. A non-loopback listener is rejected unless Gateway
+mode is explicitly enabled.
+
+Gateway mode requires a TLS certificate, its owner-only private key, and
+exactly one bearer-token source. The token can be passed through
+`HERTZBEAT_OTLP_GATEWAY_TOKEN`, or read from an owner-only local file so the
+official bearer-token extension can reload it without restarting the runtime.
+The certificate and secret file locations are local Collector configuration;
+they are never accepted as server-managed desired configuration. Spring's
+relaxed environment binding supports these local values:
+
+```shell
+export HERTZBEAT_OTLP_GATEWAY_ENABLED=true
+export HERTZBEAT_OTLP_GRPC_LISTEN_ENDPOINT=0.0.0.0:4317
+export HERTZBEAT_OTLP_HTTP_LISTEN_ENDPOINT=0.0.0.0:4318
+export
COLLECTOR_OTEL_RUNTIME_OTLP_GATEWAY_CERTIFICATE_FILE=/etc/hertzbeat/gateway.crt
+export
COLLECTOR_OTEL_RUNTIME_OTLP_GATEWAY_PRIVATE_KEY_FILE=/etc/hertzbeat/gateway.key
+export
COLLECTOR_OTEL_RUNTIME_OTLP_GATEWAY_BEARER_TOKEN_FILE=/etc/hertzbeat/gateway.token
+```
+
+Set `COLLECTOR_OTEL_RUNTIME_OTLP_GATEWAY_CLIENT_CA_FILE` to a trusted client CA
+to require mTLS in addition to the bearer token. The private key and token file
+must not be readable or writable by group or other users on POSIX systems.
+Transport timeouts, the 4 MiB body limit, the persistent 2,048-request export
+queue, and the shared memory admission budget remain bounded in both modes.
+The default 256 MiB runtime memory budget can be locally tuned within enforced
+limits; all active sources and incoming OTLP pipelines use the same limiter.
+
+Prometheus targets are bounded server-managed intent. File-log paths are
+resolved from administrator-owned local profiles, so a remote configuration
+cannot expand the Collector host's filesystem access. For example:
+
+```yaml
+collector:
+ otel-runtime:
+ prometheus-targets:
+ - name: payments
+ endpoint: https://127.0.0.1:9464/metrics
+ interval: 30s
+ timeout: 5s
+ header-secret-refs:
+ X-Scrape-Token: payments-token
+ tls-ca-profile: payments-ca
+ # Values and local certificate paths are never part of server-managed
intent.
+ prometheus-header-secrets:
+ payments-token: ${PAYMENTS_PROMETHEUS_TOKEN}
+ prometheus-tls-ca-profiles:
+ payments-ca: /etc/hertzbeat/certs/payments-ca.pem
+ file-log-allow-roots:
+ - /var/log/payments
+ file-log-deny-paths:
+ - /var/log/payments/private
+ file-log-profiles:
+ payments-logs:
+ - /var/log/payments/*.log
+ file-log-sources:
+ - name: payments
+ path-profile: payments-logs
+ environment: staging
+ resource-detectors:
+ - ENV
+ - SYSTEM
+ telemetry-filter-presets:
+ - HEALTH_CHECK_TRACES
+```
+
+## Current limits
+
+- Prometheus supports at most 32 bounded static HTTP(S) targets. Scrapes have
+ fixed sample, label and response-size ceilings; optional headers refer to
+ local secrets and HTTPS trust refers to a local CA profile. Neither value is
+ stored in server-managed intent.
+- File logs use local path profiles, start at the end by default, preserve
+ offsets across restart, and handle rename rotation and copytruncate. Policy
+ rejects traversal, recursive globs, denied paths, symlink escapes, more than
+ 16 patterns, or more than 256 existing matches before runtime validation.
+ Runtime concurrency, polling batches and line size are also bounded.
+- File offsets and the bounded downstream exporter queue use the same
+ owner-only `file_storage` directory.
+- The local control surface is the versioned loopback health contract. Managed
+ desired configuration uses the existing HertzBeat heartbeat channel; OpAMP
+ is not included.
+- The manual `Hybrid Collector Release Gate` workflow builds the Java Native
+ Collector on Linux amd64/arm64, macOS amd64/arm64, and Windows amd64. Linux
+ packages include the reviewed systemd unit; the multi-platform container uses
+ the native foreground launcher and runs as the `hertzbeat` user.
+- Automated license classification, SBOMs, vulnerability checks, checksums, and
+ Go binary reproducibility are release inputs, not a substitute for the Apache
+ release manager's LICENSE/NOTICE review, artifact signing, and vote.
diff --git a/hertzbeat-otel-runtime/builder-config.yaml
b/hertzbeat-otel-runtime/builder-config.yaml
new file mode 100644
index 0000000000..c84860a036
--- /dev/null
+++ b/hertzbeat-otel-runtime/builder-config.yaml
@@ -0,0 +1,54 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0.
+
+dist:
+ module: github.com/apache/hertzbeat/hertzbeat-otel-runtime/generated
+ name: hertzbeat-otel-runtime
+ description: HertzBeat managed OpenTelemetry runtime
+ output_path: ./_build/otelcol-hertzbeat
+ version: 2.0.0-phase1
+ build_tags: remove_all_sd
+
+# Keep the fixed SDK log API aligned with its exporters and logging bridge.
+replaces:
+ - golang.org/x/text => golang.org/x/text v0.42.0
+ - google.golang.org/grpc => google.golang.org/grpc v1.83.2
+ - golang.org/x/net => golang.org/x/net v0.60.0
+ - go.opentelemetry.io/otel/sdk => go.opentelemetry.io/otel/sdk v1.45.0
+ - go.opentelemetry.io/otel/sdk/log => go.opentelemetry.io/otel/sdk/log
v0.21.0
+ - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp =>
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.21.0
+ - go.opentelemetry.io/otel/exporters/stdout/stdoutlog =>
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.21.0
+ - go.opentelemetry.io/contrib/bridges/otelzap =>
go.opentelemetry.io/contrib/bridges/otelzap v0.20.0
+ - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc =>
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.21.0
+ - go.opentelemetry.io/otel/exporters/otlp/otlptrace =>
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0
+ - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc =>
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0
+ - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp =>
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.45.0
+
+receivers:
+ - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.156.0
+ - gomod:
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver
v0.156.0
+ - gomod:
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver
v0.156.0
+ - gomod:
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/filelogreceiver
v0.156.0
+
+processors:
+ - gomod: go.opentelemetry.io/collector/processor/memorylimiterprocessor
v0.156.0
+ - gomod:
github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourcedetectionprocessor
v0.156.0
+ - gomod:
github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourceprocessor
v0.156.0
+ - gomod:
github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor
v0.156.0
+ - gomod:
github.com/open-telemetry/opentelemetry-collector-contrib/processor/filterprocessor
v0.156.0
+ - gomod: go.opentelemetry.io/collector/processor/batchprocessor v0.156.0
+
+exporters:
+ - gomod: go.opentelemetry.io/collector/exporter/otlphttpexporter v0.156.0
+
+extensions:
+ - gomod:
github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension
v0.156.0
+ - gomod:
github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage/filestorage
v0.156.0
+ - gomod:
github.com/open-telemetry/opentelemetry-collector-contrib/extension/bearertokenauthextension
v0.156.0
+
+providers:
+ - gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.50.0
+ - gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.50.0
+ - gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.50.0
diff --git a/hertzbeat-otel-runtime/config/collector-config.test.yaml
b/hertzbeat-otel-runtime/config/collector-config.test.yaml
new file mode 100644
index 0000000000..5c31be8bed
--- /dev/null
+++ b/hertzbeat-otel-runtime/config/collector-config.test.yaml
@@ -0,0 +1,128 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0.
+
+receivers:
+ otlp:
+ protocols:
+ grpc:
+ endpoint: 127.0.0.1:14317
+ max_recv_msg_size_mib: 4
+ http:
+ endpoint: 127.0.0.1:14318
+ max_request_body_size: 4194304
+ hostmetrics:
+ collection_interval: 10s
+ scrapers:
+ cpu:
+ disk:
+ filesystem:
+ load:
+ memory:
+ network:
+ paging:
+ processes:
+ prometheus/validation:
+ config:
+ scrape_configs:
+ - job_name: validation
+ scrape_interval: 30s
+ static_configs:
+ - targets: ['127.0.0.1:19464']
+ filelog/validation:
+ include:
+ - ${env:HERTZBEAT_OTEL_TEST_LOG}
+ start_at: end
+ storage: file_storage
+ max_log_size: 1MiB
+ max_concurrent_files: 32
+
+processors:
+ memory_limiter:
+ check_interval: 1s
+ limit_mib: 256
+ spike_limit_mib: 64
+ resource_detection:
+ detectors: [env, system]
+ timeout: 2s
+ override: false
+ system:
+ hostname_sources: [os]
+ resource:
+ attributes:
+ - key: service.name
+ value: hertzbeat-otel-runtime
+ action: upsert
+ - key: hertzbeat.collector.id
+ value: ${env:HERTZBEAT_COLLECTOR_ID}
+ action: upsert
+ - key: hertzbeat.runtime
+ value: otel
+ action: upsert
+ - key: hertzbeat.workspace_id
+ value: ${env:HERTZBEAT_WORKSPACE_ID}
+ action: upsert
+ - pattern:
'(?i)^(authorization|proxy-authorization|cookie|set-cookie|x-api-key|api[-_]?key|access[-_]?token|refresh[-_]?token|http\.request\.header\.(authorization|cookie)|http\.response\.header\.set_cookie)$'
+ action: delete
+ attributes/sanitize:
+ actions:
+ - pattern:
'(?i)^(authorization|proxy-authorization|cookie|set-cookie|x-api-key|api[-_]?key|access[-_]?token|refresh[-_]?token|http\.request\.header\.(authorization|cookie)|http\.response\.header\.set_cookie)$'
+ action: delete
+ filter/health_checks:
+ error_mode: ignore
+ traces:
+ span:
+ - 'attributes["http.route"] == "/health"'
+ - 'attributes["http.route"] == "/healthz"'
+ - 'attributes["http.route"] == "/readyz"'
+ - 'attributes["http.route"] == "/livez"'
+ batch:
+ send_batch_size: 1024
+ timeout: 5s
+
+exporters:
+ otlphttp:
+ endpoint: ${env:HERTZBEAT_OTLP_HTTP_ENDPOINT}
+ headers:
+ Authorization: Bearer ${env:HERTZBEAT_OTLP_TOKEN}
+ compression: gzip
+ retry_on_failure:
+ enabled: true
+ initial_interval: 1s
+ max_interval: 30s
+ max_elapsed_time: 0s
+ sending_queue:
+ enabled: true
+ num_consumers: 4
+ block_on_overflow: false
+ sizer: requests
+ queue_size: 2048
+ storage: file_storage
+
+extensions:
+ health_check:
+ endpoint: 127.0.0.1:${env:HERTZBEAT_OTEL_HEALTH_PORT}
+ file_storage:
+ directory: ${env:HERTZBEAT_OTEL_FILE_STORAGE_DIR}
+ timeout: 1s
+ max_size: 67108864
+ fsync: true
+ create_directory: false
+ recreate: false
+
+service:
+ extensions: [health_check, file_storage]
+ pipelines:
+ metrics:
+ receivers: [hostmetrics, prometheus/validation, otlp]
+ processors: [memory_limiter, resource_detection, resource,
attributes/sanitize, batch]
+ exporters: [otlphttp]
+ logs:
+ receivers: [filelog/validation, otlp]
+ processors: [memory_limiter, resource_detection, resource,
attributes/sanitize, batch]
+ exporters: [otlphttp]
+ traces:
+ receivers: [otlp]
+ processors: [memory_limiter, resource_detection, resource,
attributes/sanitize, filter/health_checks, batch]
+ exporters: [otlphttp]
diff --git a/hertzbeat-otel-runtime/go.mod b/hertzbeat-otel-runtime/go.mod
new file mode 100644
index 0000000000..5752dd87af
--- /dev/null
+++ b/hertzbeat-otel-runtime/go.mod
@@ -0,0 +1,8 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0.
+
+module github.com/apache/hertzbeat/hertzbeat-otel-runtime
+
+go 1.26.9
diff --git a/hertzbeat-otel-runtime/runtime-manifest.json
b/hertzbeat-otel-runtime/runtime-manifest.json
new file mode 100644
index 0000000000..7c0f9f3611
--- /dev/null
+++ b/hertzbeat-otel-runtime/runtime-manifest.json
@@ -0,0 +1,9 @@
+{
+ "schemaVersion": 1,
+ "runtimeVersion": "2.0.0-phase1",
+ "otelCoreVersion": "0.156.0",
+ "otelContribVersion": "0.156.0",
+ "controlProtocol": "loopback-health-v1",
+ "desiredConfigSchema": 3,
+ "componentInventorySha256":
"5ea40cbbf99eb140df6beaba04d224eba14a7624bb1b2efb584749721a5e9e38"
+}
diff --git a/script/ci/find_maven_release_command.py
b/script/ci/find_maven_release_command.py
new file mode 100644
index 0000000000..7fbbc0c362
--- /dev/null
+++ b/script/ci/find_maven_release_command.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Find the single-line mvnd release assembly command in the backend
workflow."""
+
+from __future__ import annotations
+
+import shlex
+import sys
+from pathlib import Path
+
+
+# These options consume the next argument; their values are not Maven profiles.
+VALUE_OPTIONS = {
+ "-pl", "--projects", "-f", "--file", "-D", "--define", "-s", "--settings",
+ "-gs", "--global-settings", "-t", "--toolchains", "-gt",
"--global-toolchains",
+ "-l", "--log-file", "-rf", "--resume-from", "-T", "--threads", "-b",
"--builder",
+}
+
+
+def is_release_package_command(line: str) -> bool:
+ command = line.strip()
+ if command.startswith("run:"):
+ command = command.removeprefix("run:").strip()
+ try:
+ lexer = shlex.shlex(command, posix=True, punctuation_chars=True)
+ lexer.whitespace_split = True
+ tokens = list(lexer)
+ except ValueError:
+ return False
+ # Keep the gate's existing command contract; do not match echoed text or
+ # compound shell commands whose execution requires further interpretation.
+ if tokens[:4] != ["mvnd", "clean", "-B", "package"]:
+ return False
+ if any(token and all(char in ";&|()<>" for char in token) for token in
tokens):
+ return False
+ profiles: list[str] = []
+ index = 4
+ while index < len(tokens):
+ token = tokens[index]
+ if token in VALUE_OPTIONS:
+ index += 2
+ continue
+ if token == "-P":
+ index += 1
+ if index == len(tokens):
+ return False
+ profiles.extend(tokens[index].split(","))
+ elif token.startswith("-P"):
+ profiles.extend(token[2:].split(","))
+ index += 1
+ profiles = [profile.strip() for profile in profiles]
+ return "release" in profiles and not {"!release",
"-release"}.intersection(profiles)
+
+
+def release_package_line(text: str) -> int | None:
+ return next((number for number, line in enumerate(text.splitlines(), 1)
+ if is_release_package_command(line)), None)
+
+
+if __name__ == "__main__":
+ number = release_package_line(Path(sys.argv[1]).read_text())
+ if number is not None:
+ print(number)
diff --git a/script/ci/test_find_maven_release_command.py
b/script/ci/test_find_maven_release_command.py
new file mode 100644
index 0000000000..b529d00848
--- /dev/null
+++ b/script/ci/test_find_maven_release_command.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Regression contracts for the backend release command gate."""
+
+import unittest
+
+from script.ci.find_maven_release_command import is_release_package_command,
release_package_line
+
+
+class MavenReleaseCommandTest(unittest.TestCase):
+ def test_accepts_real_release_profiles_after_module_selection(self):
+ for command in (
+ "run: mvnd clean -B package -pl '!hertzbeat-e2e' -Prelease
-Dmaven.test.skip=false --file pom.xml",
+ "mvnd clean -B package -Prelease -pl '!hertzbeat-e2e'",
+ "mvnd clean -B package -pl '!hertzbeat-e2e' -P release",
+ "mvnd clean -B package -Pother,release",
+ ):
+ with self.subTest(command=command):
+ self.assertTrue(is_release_package_command(command))
+
+ def test_rejects_missing_fake_or_disabled_release_profiles(self):
+ for command in (
+ "mvnd clean -B package -pl '!hertzbeat-e2e'",
+ "mvnd clean -B package -Prelease-preview",
+ "mvnd clean -B package -Pprerelease",
+ "mvnd clean -B package -P!release",
+ "mvnd clean -B package -Prelease -P!release",
+ "mvnd clean -B package -Dnote=-Prelease",
+ "mvnd clean -B package -D '-Prelease'",
+ "mvnd clean -B package -pl '-Prelease'",
+ "mvnd clean -B package --log-file '-Prelease'",
+ "mvnd clean -B package # -Prelease",
+ "echo 'mvnd clean -B package -Prelease'",
+ "mvnd clean -B package; echo -Prelease",
+ "mvnd clean -B package -Prelease | cat",
+ "mvnd clean -B package '-Prelease",
+ ):
+ with self.subTest(command=command):
+ self.assertFalse(is_release_package_command(command))
+
+ def test_returns_actual_command_line_number_or_no_match(self):
+ self.assertEqual(3, release_package_line(
+ "name: Build\n# mvnd clean -B package -Prelease\n"
+ " run: mvnd clean -B package -pl '!hertzbeat-e2e' -Prelease\n"))
+ self.assertIsNone(release_package_line("run: mvnd clean -B package
-Pprerelease"))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/script/ci/verify-otel-runtime-layout.sh
b/script/ci/verify-otel-runtime-layout.sh
index b759ceff58..adbb6782cb 100755
--- a/script/ci/verify-otel-runtime-layout.sh
+++ b/script/ci/verify-otel-runtime-layout.sh
@@ -36,6 +36,12 @@ for required_file in $required_files; do
fi
done
+if ! grep -Fqx 'go 1.26.9' "$runtime_dir/go.mod" \
+ || ! grep -Fq 'export GOTOOLCHAIN := go$(GO_VERSION)'
"$runtime_dir/Makefile"; then
+ echo "runtime builds must select the reviewed Go 1.26.9 toolchain" >&2
+ exit 1
+fi
+
if grep -R "hertzbeat-collector-go" "$runtime_dir" >/dev/null 2>&1; then
echo "the new runtime must not reference the retired hertzbeat-collector-go
project" >&2
exit 1
@@ -51,14 +57,14 @@ for component in hostmetricsreceiver prometheusreceiver
filelogreceiver otlprece
fi
done
-if ! grep -Fq -- '- golang.org/x/text => golang.org/x/text v0.39.0' \
+if ! grep -Fq -- '- golang.org/x/text => golang.org/x/text v0.42.0' \
"$runtime_dir/builder-config.yaml"; then
- echo "the Runtime must pin golang.org/x/text to the reviewed
vulnerability-free version" >&2
+ echo "the Runtime must pin golang.org/x/text to the reviewed security
baseline" >&2
exit 1
fi
-if ! grep -Fqx ' - google.golang.org/grpc => google.golang.org/grpc v1.82.1' \
+if ! grep -Fqx ' - google.golang.org/grpc => google.golang.org/grpc v1.83.2' \
"$runtime_dir/builder-config.yaml"; then
- echo "generated runtime must constrain google.golang.org/grpc to v1.82.1" >&2
+ echo "generated runtime must constrain google.golang.org/grpc to v1.83.2" >&2
exit 1
fi
diff --git a/script/ci/verify-server-release-layout.sh
b/script/ci/verify-server-release-layout.sh
index 17dad01614..b36d94de22 100755
--- a/script/ci/verify-server-release-layout.sh
+++ b/script/ci/verify-server-release-layout.sh
@@ -138,7 +138,7 @@ fi
toolchain_line=$(grep -n 'corepack prepare [email protected] --activate' "$workflow"
| head -1 | cut -d: -f1 || true)
install_line=$(grep -n 'pnpm install --frozen-lockfile' "$workflow" | head -1
| cut -d: -f1 || true)
build_line=$(grep -n 'pnpm build' "$workflow" | head -1 | cut -d: -f1 || true)
-package_line=$(grep -n 'mvnd clean -B package -Prelease' "$workflow" | head -1
| cut -d: -f1 || true)
+package_line=$(python3 script/ci/find_maven_release_command.py "$workflow")
package_verify_line=$(grep -n 'verify-server-release-package.py' "$workflow" |
head -1 | cut -d: -f1 || true)
if [ -z "$toolchain_line" ] || [ -z "$install_line" ] || [ -z "$build_line" ]
|| [ -z "$package_line" ] \
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]