Files
platform-core/scripts/validate/test-capture-observability-metric-inventory.sh

752 lines
40 KiB
Bash

#!/usr/bin/env bash
set -Eeuo pipefail
readonly ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd -P)"
readonly CAPTURE="$ROOT/scripts/validate/capture-observability-metric-inventory.sh"
readonly REJECT_STATUS=23
readonly ORIGINAL_PATH="$PATH"
fail() {
printf 'TEST FAILURE: %s\n' "$*" >&2
exit 1
}
expect_pass() {
local name="$1" output
shift
if ! output="$({ "$@"; } 2>&1)"; then
fail "$name (expected success): $output"
fi
pass_count=$((pass_count + 1))
}
expect_reject() {
local name="$1" output rc=0
shift
output="$({ "$@"; } 2>&1)" || rc=$?
[[ "$rc" == "$REJECT_STATUS" ]] || fail "$name (expected $REJECT_STATUS, got $rc): $output"
[[ "$output" == REJECT:* ]] || fail "$name (unsanitized rejection): $output"
[[ "$output" != *DO-NOT-LEAK-FIXTURE* ]] || fail "$name leaked a fixture value"
pass_count=$((pass_count + 1))
}
[[ -f "$CAPTURE" ]] || fail "EXPECTED RED: capture command is missing: $CAPTURE"
# shellcheck source=/dev/null
source "$CAPTURE"
fixture_root="$(mktemp -d /tmp/platform-observability-inventory-test.XXXXXX)"
test_helper_pids=()
cleanup() {
local rc=$?
local helper_pid
for helper_pid in "${test_helper_pids[@]}"; do
if [[ "$helper_pid" =~ ^[0-9]+$ ]]; then kill -KILL "$helper_pid" 2>/dev/null || true; fi
done
if [[ "${KEEP_INVENTORY_TEST_FIXTURE:-0}" == 1 ]]; then
printf 'KEPT FIXTURE: %s\n' "$fixture_root" >&2
exit "$rc"
fi
case "$fixture_root" in
/tmp/platform-observability-inventory-test.*) rm -rf -- "$fixture_root" ;;
*) printf 'TEST FAILURE: refusing unsafe fixture cleanup\n' >&2; rc=1 ;;
esac
exit "$rc"
}
trap cleanup EXIT
pass_count=0
mapfile -t exact_pools <<'POOLS'
podMonitor/platform-data/platform-postgres/0
serviceMonitor/gitea/gitea/0
serviceMonitor/keycloak/keycloak/0
serviceMonitor/kube-system/traefik/0
serviceMonitor/object-storage/aistor-bucket-usage/0
serviceMonitor/observability-agent/alloy/0
serviceMonitor/observability-agent/node-exporter/0
serviceMonitor/observability/grafana/0
serviceMonitor/observability/loki/0
serviceMonitor/observability/observability-core-kube-pr-alertmanager/0
serviceMonitor/observability/observability-core-kube-pr-alertmanager/1
serviceMonitor/observability/observability-core-kube-pr-apiserver/0
serviceMonitor/observability/observability-core-kube-pr-coredns/0
serviceMonitor/observability/observability-core-kube-pr-kubelet/0
serviceMonitor/observability/observability-core-kube-pr-kubelet/1
serviceMonitor/observability/observability-core-kube-pr-kubelet/2
serviceMonitor/observability/observability-core-kube-pr-operator/0
serviceMonitor/observability/observability-core-kube-pr-prometheus/0
serviceMonitor/observability/observability-core-kube-pr-prometheus/1
serviceMonitor/observability/observability-core-kube-state-metrics/0
serviceMonitor/observability/tempo/0
POOLS
expected_target_selectors="$fixture_root/expected-target-selectors"
expected_series_selectors="$fixture_root/expected-series-selectors"
: >"$expected_target_selectors"
: >"$expected_series_selectors"
make_targets() {
local destination="$1" pool labels selector series_selector index=0
local rows="$fixture_root/target-rows.jsonl"
: >"$rows"
for pool in "${exact_pools[@]}"; do
labels="$(jq -cn --arg instance "10.0.0.$((index + 1)):9090" --arg target "target-$index" \
'{job:"fixture-job",instance:$instance,sensitive_fixture:"DO-NOT-LEAK-FIXTURE",target_fixture:$target}')"
selector="{instance=\"10.0.0.$((index + 1)):9090\",job=\"fixture-job\",sensitive_fixture=\"DO-NOT-LEAK-FIXTURE\",target_fixture=\"target-$index\"}"
if [[ "$pool" == serviceMonitor/object-storage/aistor-bucket-usage/0 ]]; then
labels="$(jq -cn --arg target "target-$index" \
'{job:"minio-aistor",namespace:"object-storage",service:"minio",endpoint:"http-minio",
container:"minio",instance:"10.42.7.19:9000",pod:"minio-aistor-pool-0-0",
sensitive_fixture:"DO-NOT-LEAK-FIXTURE",target_fixture:$target}')"
selector="{container=\"minio\",endpoint=\"http-minio\",instance=\"10.42.7.19:9000\",job=\"minio-aistor\",namespace=\"object-storage\",pod=\"minio-aistor-pool-0-0\",sensitive_fixture=\"DO-NOT-LEAK-FIXTURE\",service=\"minio\",target_fixture=\"target-$index\"}"
fi
printf '%s\n' "$selector" >>"$expected_target_selectors"
series_selector="{__name__=\"fixture_metric\",${selector#\{}"
printf '%s\n' "$series_selector" >>"$expected_series_selectors"
jq -cn \
--arg pool "$pool" \
--arg url "http://10.42.0.$((index + 1)):9090/metrics" \
--argjson labels "$labels" \
'{discoveredLabels:$labels,labels:$labels,scrapePool:$pool,scrapeUrl:$url,
globalUrl:$url,lastError:"",lastScrape:"2026-08-12T00:00:00Z",
lastScrapeDuration:0.01,health:"up",scrapeInterval:"30s",scrapeTimeout:"10s"}' \
>>"$rows"
index=$((index + 1))
done
jq -cs '{status:"success",data:{activeTargets:.,droppedTargets:[]}}' "$rows" >"$destination"
}
valid_targets="$fixture_root/targets.json"
make_targets "$valid_targets"
oversized_padding="$fixture_root/oversized-padding"
head -c 8388609 /dev/zero | tr '\000' x >"$oversized_padding"
oversized_targets="$fixture_root/oversized-targets.json"
jq --rawfile padding "$oversized_padding" '. + {padding:$padding}' "$valid_targets" >"$oversized_targets"
expect_pass 'exact 21 active pools accepted' validate_targets_json "$valid_targets"
post_targets="$fixture_root/post-targets.json"
post_probe_rows="$fixture_root/post-probe-rows.json"
post_substrate_expected_probe_targets | jq '[.[] as $target | $target + {
discoveredLabels:$target.labels,globalUrl:$target.scrapeUrl,lastError:"",
lastScrape:"2026-08-12T00:00:00Z",lastScrapeDuration:0.01,
health:"up",scrapeInterval:"30s",scrapeTimeout:"15s"}]' >"$post_probe_rows"
jq --slurpfile probes "$post_probe_rows" '
.data.activeTargets += ($probes[0] + [{
discoveredLabels:{},
labels:{job:"blackbox-exporter",namespace:"observability",service:"blackbox-exporter",
endpoint:"http",container:"blackbox-exporter",pod:"blackbox-exporter-6d8444ffdb-svsck",
instance:"10.42.0.123:9115"},
scrapePool:"serviceMonitor/observability/blackbox-exporter/0",
scrapeUrl:"http://10.42.0.123:9115/metrics",globalUrl:"http://10.42.0.123:9115/metrics",
lastError:"",lastScrape:"2026-08-12T00:00:00Z",lastScrapeDuration:0.01,
health:"up",scrapeInterval:"30s",scrapeTimeout:"10s"
}])
' "$valid_targets" >"$post_targets"
expect_pass 'exact post-substrate 30 targets and multiplicities accepted' \
validate_targets_json "$post_targets" post-substrate
expect_reject 'post-substrate targets rejected by target-initial phase' \
validate_targets_json "$post_targets" target-initial
post_missing_probe="$fixture_root/post-missing-probe.json"
jq 'del(.data.activeTargets[] | select(.scrapePool=="probe/observability/platform-public-edge"))' \
"$post_targets" >"$post_missing_probe"
expect_reject 'post-substrate missing Probe target rejected' \
validate_targets_json "$post_missing_probe" post-substrate
expect_pass 'Probe query is removed from persisted scrape URL' \
test "$(sanitize_scrape_url 'http://blackbox-exporter.observability.svc.cluster.local:9115/probe?module=http_2xx&target=https%3A%2F%2Fexample.test' strip-query)" = \
'http://blackbox-exporter.observability.svc.cluster.local:9115/probe'
expect_pass 'UTF-8 Prometheus label key is quoted in selector' \
test "$(prometheus_selector_for_labels '{"job":"blackbox","observability.hyeonworks.com/probe-group":"public-edge"}')" = \
'{job="blackbox","observability.hyeonworks.com/probe-group"="public-edge"}'
mutate_and_reject() {
local name="$1" filter="$2" destination
destination="$fixture_root/${name// /-}.json"
jq "$filter" "$valid_targets" >"$destination"
expect_reject "$name" validate_targets_json "$destination"
}
mutate_and_reject 'missing pool rejected' 'del(.data.activeTargets[0])'
mutate_and_reject 'extra pool rejected' '.data.activeTargets += [.data.activeTargets[0] | .scrapePool="serviceMonitor/extra/extra/0"]'
mutate_and_reject 'duplicate pool rejected' '.data.activeTargets += [.data.activeTargets[0]]'
mutate_and_reject 'down target rejected' '.data.activeTargets[0].health="down"'
mutate_and_reject 'last error rejected' '.data.activeTargets[0].lastError="DO-NOT-LEAK-FIXTURE"'
mutate_and_reject 'blackbox pool rejected' '.data.activeTargets[0].scrapePool="serviceMonitor/observability/blackbox-exporter/0"'
mutate_and_reject 'Probe pool rejected' '.data.activeTargets[0].scrapePool="probe/observability/public-edge/0"'
dropped_blackbox="$fixture_root/dropped-blackbox.json"
jq '.data.droppedTargets = [{
"discoveredLabels": {
"__meta_kubernetes_namespace": "observability",
"__meta_kubernetes_service_name": "blackbox-exporter",
"job": "blackbox-exporter"
},
"labels": {"job": "blackbox-exporter"},
"scrapePool": "serviceMonitor/observability/blackbox-exporter/0",
"scrapeUrl": "http://blackbox-exporter.observability.svc:9115/metrics",
"globalUrl": "http://blackbox-exporter.observability.svc:9115/metrics",
"lastError": "",
"health": "unknown"
}]' "$valid_targets" >"$dropped_blackbox"
expect_reject 'dropped blackbox identity rejected' validate_targets_json "$dropped_blackbox"
expect_pass 'post-substrate allows blackbox self discovery drops' \
validate_dropped_targets_json "$dropped_blackbox" post-substrate
dropped_probe="$fixture_root/dropped-probe.json"
jq '.data.droppedTargets = [{
"discoveredLabels": {
"__meta_kubernetes_namespace": "observability",
"__meta_kubernetes_service_name": "synthetic-exporter",
"monitor_kind": "Probe"
},
"labels": {"job": "synthetic-checks"},
"scrapePool": "probe/observability/public-edge/0",
"scrapeUrl": "http://synthetic-exporter.observability.svc:9115/metrics",
"globalUrl": "http://synthetic-exporter.observability.svc:9115/metrics",
"lastError": "",
"health": "unknown"
}]' "$valid_targets" >"$dropped_probe"
expect_reject 'dropped Probe identity rejected' validate_targets_json "$dropped_probe"
legitimate_probe_word="$fixture_root/legitimate-probe-word.json"
jq '.data.droppedTargets = [{
"discoveredLabels": {
"__meta_kubernetes_pod_annotation_fixture": "{\"livenessProbe\":true}",
"__metrics_path__": "/metrics/probes"
},
"labels": {"job": "platform-postgres"},
"scrapePool": "podMonitor/platform-data/platform-postgres/0",
"scrapeUrl": "http://10.42.0.1:9187/metrics/probes",
"globalUrl": "http://10.42.0.1:9187/metrics/probes",
"lastError": "",
"health": "unknown"
}]' "$valid_targets" >"$legitimate_probe_word"
expect_pass 'legitimate dropped metadata containing probe words accepted in active response' \
validate_targets_json "$legitimate_probe_word"
expect_pass 'legitimate dropped metadata containing probe words accepted in dropped response' \
validate_dropped_targets_json "$legitimate_probe_word"
empty_dropped_targets="$fixture_root/empty-dropped-targets.json"
printf '%s\n' '{"status":"success","data":{"activeTargets":[],"droppedTargets":[]}}' >"$empty_dropped_targets"
mutate_and_reject 'AIStor wrong job rejected' '(.data.activeTargets[] | select(.scrapePool=="serviceMonitor/object-storage/aistor-bucket-usage/0") | .labels.job)="wrong"'
mutate_and_reject 'AIStor wrong namespace rejected' '(.data.activeTargets[] | select(.scrapePool=="serviceMonitor/object-storage/aistor-bucket-usage/0") | .labels.namespace)="wrong"'
mutate_and_reject 'AIStor wrong service rejected' '(.data.activeTargets[] | select(.scrapePool=="serviceMonitor/object-storage/aistor-bucket-usage/0") | .labels.service)="wrong"'
mutate_and_reject 'AIStor wrong endpoint rejected' '(.data.activeTargets[] | select(.scrapePool=="serviceMonitor/object-storage/aistor-bucket-usage/0") | .labels.endpoint)="wrong"'
mutate_and_reject 'AIStor wrong container rejected' '(.data.activeTargets[] | select(.scrapePool=="serviceMonitor/object-storage/aistor-bucket-usage/0") | .labels.container)="wrong"'
expect_pass 'safe HTTP URL accepted' test "$(sanitize_scrape_url 'http://10.42.7.19:9000/minio/metrics/v3/cluster/usage/buckets')" = 'http://10.42.7.19:9000/minio/metrics/v3/cluster/usage/buckets'
expect_pass 'safe HTTPS URL accepted' test "$(sanitize_scrape_url 'https://metrics.example.test/metrics')" = 'https://metrics.example.test/metrics'
for unsafe_url in \
'http://user:DO-NOT-LEAK-FIXTURE@host/metrics' \
'http://host/metrics?token=DO-NOT-LEAK-FIXTURE' \
'http://host/metrics#DO-NOT-LEAK-FIXTURE' \
'ftp://host/metrics' \
'http://host/space here'; do
expect_reject 'unsafe scrape URL rejected' sanitize_scrape_url "$unsafe_url"
done
metadata="$fixture_root/metadata.json"
printf '%s\n' '{"status":"success","data":{"z_metric":[{"type":"gauge","help":"DO-NOT-LEAK-FIXTURE","unit":""}],"a_metric":[{"type":"counter","help":"ignored","unit":""}]}}' >"$metadata"
expect_pass 'metadata metric names sorted' test "$(extract_metric_names "$metadata")" = $'a_metric\nz_metric'
metadata_array="$fixture_root/metadata-array.json"
printf '%s\n' '{"status":"success","data":[{"target":{"job":"fixture"},"metric":"z_metric","type":"gauge","help":"DO-NOT-LEAK-FIXTURE","unit":""},{"target":{"job":"fixture"},"metric":"a_metric","type":"counter","help":"ignored","unit":""},{"target":{"job":"fixture"},"metric":"z_metric","type":"gauge","help":"duplicate","unit":""}]}' >"$metadata_array"
expect_pass 'current Prometheus metadata array yields unique sorted metric names' \
test "$(extract_metric_names "$metadata_array")" = $'a_metric\nz_metric'
bad_metadata_array="$fixture_root/bad-metadata-array.json"
printf '%s\n' '{"status":"success","data":[{"target":{},"metric":"bad metric","type":"gauge","help":"ignored","unit":""}]}' >"$bad_metadata_array"
expect_reject 'invalid current metadata array metric name rejected' extract_metric_names "$bad_metadata_array"
expect_pass 'post-substrate Probe pool accepts probe metrics' \
validate_metric_names_for_pool $'probe_duration_seconds\nprobe_success' \
probe/observability/platform-public-edge post-substrate
expect_reject 'target-initial rejects probe metrics' \
validate_metric_names_for_pool probe_success serviceMonitor/observability/grafana/0 target-initial
expect_reject 'post-substrate non-Probe pool rejects probe metrics' \
validate_metric_names_for_pool probe_success serviceMonitor/observability/blackbox-exporter/0 post-substrate
expect_reject 'post-substrate Probe pool requires probe_success descriptor' \
validate_metric_names_for_pool probe_duration_seconds probe/observability/platform-public-edge post-substrate
bad_metadata="$fixture_root/bad-metadata.json"
printf '%s\n' '{"status":"success","data":{"bad metric":[]}}' >"$bad_metadata"
expect_reject 'invalid metadata metric name rejected' extract_metric_names "$bad_metadata"
rules="$fixture_root/rules.json"
printf '%s\n' '{"status":"success","data":{"groups":[{"name":"fixture","rules":[{"type":"recording","name":"z_metric","query":"DO-NOT-LEAK-FIXTURE"},{"type":"alerting","name":"a_metric"}]}]}}' >"$rules"
expect_reject 'recording-rule collision rejected' reject_recording_rule_collisions "$rules" "$metadata"
printf '%s\n' '{"status":"success","data":{"groups":[{"name":"fixture","rules":[{"type":"recording","name":"recorded_metric"}]}]}}' >"$rules"
expect_pass 'non-colliding recording rule accepted' reject_recording_rule_collisions "$rules" "$metadata"
series="$fixture_root/series.json"
printf '%s\n' '{"status":"success","data":[{"z_label":"DO-NOT-LEAK-FIXTURE","__name__":"a_metric","a_label":"private-value"},{"__name__":"a_metric","middle":"another-private-value"}]}' >"$series"
expect_pass 'series parser emits only sorted label keys' test "$(extract_series_label_names "$series")" = '["__name__","a_label","middle","z_label"]'
[[ "$(extract_series_label_names "$series")" != *private-value* ]] || fail 'series parser persisted label values'
dotted_series="$fixture_root/dotted-series.json"
printf '%s\n' '{"status":"success","data":[{"__name__":"probe_success","instance":"https://example.test/","job":"blackbox-public-edge","namespace":"observability","observability.hyeonworks.com/probe-group":"public-edge"}]}' >"$dotted_series"
expect_pass 'series parser preserves safe quoted Prometheus label names' \
test "$(extract_series_label_names "$dotted_series")" = \
'["__name__","instance","job","namespace","observability.hyeonworks.com/probe-group"]'
empty_probe_series="$fixture_root/empty-probe-series.json"
printf '%s\n' '{"status":"success","data":[]}' >"$empty_probe_series"
expect_pass 'target-initial requires probe series absence' \
validate_probe_series_phase "$empty_probe_series" target-initial
expect_reject 'post-substrate rejects probe series absence' \
validate_probe_series_phase "$empty_probe_series" post-substrate
expect_pass 'post-substrate accepts observability probe series' \
validate_probe_series_phase "$dotted_series" post-substrate
expect_reject 'target-initial rejects existing probe series' \
validate_probe_series_phase "$dotted_series" target-initial
post_labels="$fixture_root/post-labels.json"
post_substrate_expected_probe_targets | jq '[.[].labels]' >"$post_labels"
for query_kind in success status duration tls; do
query_fixture="$fixture_root/post-query-$query_kind.json"
jq -cn --slurpfile labels "$post_labels" --arg kind "$query_kind" '
($labels[0] | if $kind=="tls" then map(select(.instance|startswith("https://"))) else . end) as $selected |
{status:"success",data:{resultType:"vector",result:[$selected[] |
{metric:(. + {__name__:(if $kind=="success" then "probe_success"
elif $kind=="status" then "probe_http_status_code"
elif $kind=="duration" then "probe_duration_seconds"
else "probe_ssl_earliest_cert_expiry" end)}),
value:[1770000000,(if $kind=="success" then "1"
elif $kind=="status" then (if .job=="blackbox-private-edge" then "403" else "200" end)
elif $kind=="duration" then "0.1" else "4102444800" end)]}]}}
' >"$query_fixture"
expect_pass "post-substrate $query_kind query contract accepted" \
validate_post_substrate_query_body "$query_fixture" "$query_kind"
done
large_target_rows="$fixture_root/large-target-rows.jsonl"
awk 'BEGIN {
for (i = 0; i < 20000; i++)
printf "{\"scrape_pool\":\"pool/%d\",\"scrape_url\":\"http://10.42.0.1:9090/metrics\",\"health\":\"up\",\"last_error\":\"\",\"provenance\":\"core\",\"metrics\":[{\"name\":\"fixture_metric\",\"label_names\":[\"__name__\",\"instance\"]}]}\n", i
}' >"$large_target_rows"
large_inventory_contract() {
[[ "$(stat -c %s "$large_target_rows")" -gt 2097152 ]] || return 1
build_inventory_json "$large_target_rows" target-initial 2026-08-12T00:00:00Z |
jq -e '.phase=="target-initial" and (.targets|length)==20000' >/dev/null
}
expect_pass 'inventory builder reads target rows from file beyond argv size limit' large_inventory_contract
fake_bin="$fixture_root/bin"
mkdir -p "$fake_bin"
fake_log="$fixture_root/fake-commands.log"
pf_log="$fixture_root/port-forward-pids.log"
: >"$fake_log"
: >"$pf_log"
cat >"$fake_bin/kubectl" <<'FAKE_KUBECTL'
#!/usr/bin/env bash
set -Eeuo pipefail
printf 'kubectl' >>"$FAKE_LOG"
printf ' <%s>' "$@" >>"$FAKE_LOG"
printf '\n' >>"$FAKE_LOG"
args=" $* "
if [[ "$args" =~ [[:space:]](apply|delete|patch|replace|exec|rollout|scale)[[:space:]] ]]; then
exit 91
fi
if [[ "$args" == *' config current-context '* ]]; then printf 'default\n'; exit 0; fi
if [[ "$args" == *' config view '* ]]; then printf '%s\n' '{"clusters":[{"cluster":{"server":"https://127.0.0.1:6443"}}]}'; exit 0; fi
if [[ "$args" == *' get --raw=/readyz '* ]]; then printf 'ok\n'; exit 0; fi
if [[ "$args" == *' auth can-i '* ]]; then printf 'yes\n'; exit 0; fi
if [[ "$args" == *' get prometheus '* ]]; then printf '%s\n' '{"apiVersion":"monitoring.coreos.com/v1","kind":"Prometheus","metadata":{"name":"observability-core-kube-pr-prometheus","namespace":"observability"}}'; exit 0; fi
if [[ "$args" == *' get pods '* ]]; then printf '%s\n' '{"items":[{"metadata":{"name":"prometheus-observability-core-kube-pr-prometheus-0","namespace":"observability"},"status":{"phase":"Running","conditions":[{"type":"Ready","status":"True"}],"containerStatuses":[{"name":"prometheus","ready":true}]}}]}'; exit 0; fi
if [[ "$args" == *' port-forward '* ]]; then
printf '%s\n' "$$" >>"$PF_LOG"
pf_stderr_path="$(readlink -- "/proc/$$/fd/2")"
printf '%s\n' "${pf_stderr_path%/*}" >>"$PF_WORKDIR_LOG"
if [[ "${PF_IGNORE_TERM:-0}" == 1 ]]; then
trap 'printf "ignored %s TERM\n" "$$" >>"$PF_LOG"' TERM
else
trap 'printf "stopped %s TERM\n" "$$" >>"$PF_LOG"; exit 0' TERM
fi
trap 'printf "stopped %s INT\n" "$$" >>"$PF_LOG"; exit 0' INT
trap 'printf "stopped %s HUP\n" "$$" >>"$PF_LOG"; exit 0' HUP
if [[ "${PF_NO_ANNOUNCEMENT:-0}" != 1 ]]; then
printf 'Forwarding from 127.0.0.1:43123 -> 9090\n' >&2
fi
while :; do /usr/bin/sleep 0.05; done
fi
exit 1
FAKE_KUBECTL
cat >"$fake_bin/curl" <<'FAKE_CURL'
#!/usr/bin/env bash
set -Eeuo pipefail
[[ "${1-}" == --disable ]] || exit 92
printf 'curl' >>"$FAKE_LOG"
printf ' <%s>' "$@" >>"$FAKE_LOG"
printf '\n' >>"$FAKE_LOG"
destination=''
url=''
max_filesize=''
all_arguments=" $* "
declare -a data_values=()
declare -a urlencode_values=()
while (($#)); do
case "$1" in
--output) destination="$2"; shift 2 ;;
--max-filesize) max_filesize="$2"; shift 2 ;;
--data) data_values+=("$2"); shift 2 ;;
--data-urlencode) urlencode_values+=("$2"); shift 2 ;;
http://*) url="$1"; shift ;;
*) shift ;;
esac
done
[[ -n "$destination" && -n "$url" ]] || exit 2
emit_text() {
if [[ "$destination" == - ]]; then printf '%s\n' "$1"; else printf '%s\n' "$1" >"$destination"; fi
}
emit_file() {
if [[ "$destination" == - ]]; then cat -- "$1"; else cp -- "$1" "$destination"; fi
}
case "$url" in
*/-/ready) emit_text 'ready' ;;
*/api/v1/targets)
[[ "${#data_values[@]}" == 1 ]] || exit 80
case "${data_values[0]}" in
state=dropped)
if [[ "${FAKE_CURL_MODE:-success}" == dropped_blackbox ]]; then
emit_file "$DROPPED_BLACKBOX_FIXTURE"
else
emit_file "$DROPPED_TARGETS_FIXTURE"
fi
exit 0
;;
state=active) ;;
*) exit 81 ;;
esac
if [[ "${FAKE_CURL_MODE:-success}" == hang ]]; then
trap 'exit 128' INT TERM HUP
while :; do /usr/bin/sleep 0.05; done
fi
if [[ "${FAKE_CURL_MODE:-success}" == error ]]; then exit 22; fi
if [[ "${FAKE_CURL_MODE:-success}" == oversized_targets ]]; then
[[ "$max_filesize" =~ ^[0-9]+$ ]] || exit 88
if (( $(stat -c %s "$OVERSIZED_TARGETS_FIXTURE") > max_filesize )); then exit 63; fi
emit_file "$OVERSIZED_TARGETS_FIXTURE"
else
emit_file "$TARGETS_FIXTURE"
fi
;;
*/api/v1/rules) emit_text '{"status":"success","data":{"groups":[]}}' ;;
*/api/v1/targets/metadata)
[[ "${#urlencode_values[@]}" == 1 && "${urlencode_values[0]}" == match_target=* ]] || exit 84
[[ "${#data_values[@]}" == 1 && "${data_values[0]}" == 'limit=10000' ]] || exit 85
target_selector="${urlencode_values[0]#match_target=}"
grep -Fqx -- "$target_selector" "$EXPECTED_TARGET_SELECTORS" || exit 86
printf '%s\n' "$target_selector" >>"$METADATA_SELECTOR_LOG"
emit_text '{"status":"success","data":{"descriptor_only_metric":[{"type":"gauge","help":"registered without a current series","unit":""}],"fixture_metric":[{"type":"gauge","help":"DO-NOT-LEAK-FIXTURE","unit":""}]}}'
;;
*/api/v1/series)
if [[ "$all_arguments" == *'probe_.+'* ]]; then
[[ "${#urlencode_values[@]}" == 1 && "${urlencode_values[0]}" == 'match[]={__name__=~"probe_.+"}' ]] || exit 87
emit_text '{"status":"success","data":[]}'
else
[[ "${#urlencode_values[@]}" == 1 && "${urlencode_values[0]}" == match\[\]=* ]] || exit 89
series_selector="${urlencode_values[0]#match[]=}"
if [[ "$series_selector" == *'__name__="descriptor_only_metric"'* ]]; then
fixture_selector="${series_selector/descriptor_only_metric/fixture_metric}"
grep -Fqx -- "$fixture_selector" "$EXPECTED_SERIES_SELECTORS" || exit 90
emit_text '{"status":"success","data":[]}'
exit 0
fi
grep -Fqx -- "$series_selector" "$EXPECTED_SERIES_SELECTORS" || exit 90
if [[ "${FAKE_CURL_MODE:-success}" == all_series_empty ]]; then
emit_text '{"status":"success","data":[]}'
exit 0
fi
printf '%s\n' "$series_selector" >>"$SERIES_SELECTOR_LOG"
if [[ "${FAKE_CURL_MODE:-success}" == hang_series ]]; then
printf '%s\n' "$$" >>"$CURL_PID_LOG"
: >"$CURL_HANG_MARKER"
trap 'exit 128' INT TERM HUP
while :; do /usr/bin/sleep 0.05; done
fi
emit_text '{"status":"success","data":[{"__name__":"fixture_metric","instance":"10.42.0.1:9090","secret_label":"DO-NOT-LEAK-FIXTURE"}]}'
fi
;;
*) exit 3 ;;
esac
FAKE_CURL
cat >"$fake_bin/ln" <<'FAKE_LN'
#!/usr/bin/env bash
set -Eeuo pipefail
if [[ "${FAIL_SHA_LINK:-0}" == 1 && "${*: -1}" == */inventory.sha256 ]]; then
exit 1
fi
exec /usr/bin/ln "$@"
FAKE_LN
chmod 0700 "$fake_bin/kubectl" "$fake_bin/curl" "$fake_bin/ln"
export PATH="$fake_bin:$ORIGINAL_PATH"
pf_workdir_log="$fixture_root/port-forward-workdirs.log"
curl_pid_log="$fixture_root/curl-pids.log"
metadata_selector_log="$fixture_root/metadata-selectors.log"
series_selector_log="$fixture_root/series-selectors.log"
: >"$pf_workdir_log"
: >"$curl_pid_log"
: >"$metadata_selector_log"
: >"$series_selector_log"
export FAKE_LOG="$fake_log" PF_LOG="$pf_log" PF_WORKDIR_LOG="$pf_workdir_log"
export CURL_PID_LOG="$curl_pid_log" TARGETS_FIXTURE="$valid_targets" OVERSIZED_TARGETS_FIXTURE="$oversized_targets"
export DROPPED_TARGETS_FIXTURE="$empty_dropped_targets" DROPPED_BLACKBOX_FIXTURE="$dropped_blackbox"
export EXPECTED_TARGET_SELECTORS="$expected_target_selectors" EXPECTED_SERIES_SELECTORS="$expected_series_selectors"
export METADATA_SELECTOR_LOG="$metadata_selector_log" SERIES_SELECTOR_LOG="$series_selector_log"
run_capture() {
local output_dir="$1"
shift
env PATH="$PATH" FAKE_LOG="$FAKE_LOG" PF_LOG="$PF_LOG" TARGETS_FIXTURE="$TARGETS_FIXTURE" \
PF_WORKDIR_LOG="$PF_WORKDIR_LOG" CURL_PID_LOG="$CURL_PID_LOG" \
EXPECTED_TARGET_SELECTORS="$EXPECTED_TARGET_SELECTORS" EXPECTED_SERIES_SELECTORS="$EXPECTED_SERIES_SELECTORS" \
METADATA_SELECTOR_LOG="$METADATA_SELECTOR_LOG" SERIES_SELECTOR_LOG="$SERIES_SELECTOR_LOG" \
DROPPED_TARGETS_FIXTURE="$DROPPED_TARGETS_FIXTURE" DROPPED_BLACKBOX_FIXTURE="$DROPPED_BLACKBOX_FIXTURE" \
OVERSIZED_TARGETS_FIXTURE="$OVERSIZED_TARGETS_FIXTURE" \
FAKE_CURL_MODE="${FAKE_CURL_MODE:-success}" \
bash "$CAPTURE" --execute --phase target-initial --output-dir "$output_dir" "$@"
}
inventory_kubectl_alias() { inventory_kubectl "$@"; }
mutation_log_lines="$(wc -l <"$fake_log")"
for wrapper_name in inventory_kubectl inventory_kubectl_alias; do
for mutation_verb in apply create delete patch replace exec rollout scale; do
expect_reject "$wrapper_name default-denies $mutation_verb" \
"$wrapper_name" "$mutation_verb" fixture
done
done
[[ "$(wc -l <"$fake_log")" == "$mutation_log_lines" ]] || fail 'denied wrapper mutation reached kubectl'
ownership_signal_log="$fixture_root/ownership-signals.log"
ownership_ready="$fixture_root/ownership-ready"
bash -c '
trap '\''printf "TERM\n" >>"$1"; exit 0'\'' TERM
: >"$2"
while :; do /usr/bin/sleep 0.05; done
' bash "$ownership_signal_log" "$ownership_ready" &
ownership_pid=$!
test_helper_pids+=("$ownership_pid")
for ((attempt=0; attempt<40; attempt++)); do [[ -e "$ownership_ready" ]] && break; sleep 0.025; done
[[ -e "$ownership_ready" ]] || fail 'ownership fixture did not start'
ownership_snapshot="$(inventory_process_snapshot "$ownership_pid")" || fail 'ownership fixture snapshot failed'
INVENTORY_PORT_FORWARD_PID="$ownership_pid"
INVENTORY_PORT_FORWARD_START="$((10#${ownership_snapshot#*:} + 1))"
expect_pass 'wrong start-time PID is not signaled' inventory_stop_port_forward
[[ ! -s "$ownership_signal_log" ]] || fail 'wrong start-time process received TERM'
kill -0 "$ownership_pid" 2>/dev/null || fail 'wrong start-time process was killed'
kill -TERM "$ownership_pid" 2>/dev/null || true
for ((attempt=0; attempt<40; attempt++)); do kill -0 "$ownership_pid" 2>/dev/null || break; sleep 0.025; done
cli_dir="$fixture_root/cli"
mkdir -m 0700 "$cli_dir"
expect_reject 'missing CLI arguments rejected' bash "$CAPTURE"
expect_reject 'missing execute rejected' bash "$CAPTURE" --phase target-initial --output-dir "$cli_dir"
expect_reject 'duplicate argument rejected' bash "$CAPTURE" --execute --phase target-initial --phase target-initial --output-dir "$cli_dir"
expect_reject 'unknown phase rejected' bash "$CAPTURE" --execute --phase future-phase --output-dir "$cli_dir"
expect_reject 'unknown argument rejected' bash "$CAPTURE" --execute --phase target-initial --output-dir "$cli_dir" --unknown
relative_dir="${cli_dir#/}"
expect_reject 'relative output path rejected' bash "$CAPTURE" --execute --phase target-initial --output-dir "$relative_dir"
noncanonical="$fixture_root/../$(basename "$fixture_root")/cli"
expect_reject 'noncanonical output path rejected' bash "$CAPTURE" --execute --phase target-initial --output-dir "$noncanonical"
chmod 0755 "$cli_dir"
expect_reject 'non-0700 output directory rejected' run_capture "$cli_dir"
chmod 0700 "$cli_dir"
ln -s "$cli_dir" "$fixture_root/cli-link"
expect_reject 'symlink output directory rejected' run_capture "$fixture_root/cli-link"
mkdir -m 0700 "$fixture_root/unsafe-parent"
mkdir -m 0700 "$fixture_root/real-child"
ln -s "$fixture_root/unsafe-parent" "$fixture_root/parent-link"
mkdir -m 0700 "$fixture_root/unsafe-parent/child"
expect_reject 'symlink path component rejected' run_capture "$fixture_root/parent-link/child"
printf 'preserve-me\n' >"$cli_dir/preexisting"
expect_reject 'nonempty output directory rejected without clobber' run_capture "$cli_dir"
[[ "$(cat "$cli_dir/preexisting")" == preserve-me ]] || fail 'preexisting file was modified'
rm "$cli_dir/preexisting"
empty_series_dir="$fixture_root/empty-series"
mkdir -m 0700 "$empty_series_dir"
FAKE_CURL_MODE=all_series_empty
export FAKE_CURL_MODE
expect_reject 'target with metadata descriptors but no actual series rejected' run_capture "$empty_series_dir"
unset FAKE_CURL_MODE
[[ -z "$(find "$empty_series_dir" -mindepth 1 -maxdepth 1 -print -quit)" ]] || fail 'empty-series response produced accepted output'
: >"$metadata_selector_log"
: >"$series_selector_log"
success_dir="$fixture_root/success"
mkdir -m 0700 "$success_dir"
expect_pass 'full capture succeeds with fixture APIs' run_capture "$success_dir"
cmp -s <(sort "$expected_target_selectors") <(sort "$metadata_selector_log") || fail 'metadata calls did not cover every exact full-label selector once'
cmp -s <(sort "$expected_series_selectors") <(sort "$series_selector_log") || fail 'series calls did not cover every exact metric selector once'
mapfile -t output_names < <(find "$success_dir" -mindepth 1 -maxdepth 1 -printf '%f\n' | sort)
[[ "${output_names[*]}" == 'inventory.json inventory.sha256' ]] || fail 'capture did not create exactly two files'
for output_name in "${output_names[@]}"; do
[[ -f "$success_dir/$output_name" && ! -L "$success_dir/$output_name" ]] || fail "$output_name is not a regular non-symlink"
[[ "$(stat -c %a "$success_dir/$output_name")" == 600 ]] || fail "$output_name mode is not 0600"
done
[[ "$(jq -cS . "$success_dir/inventory.json")"$'\n' == "$(cat "$success_dir/inventory.json")"$'\n' ]] || fail 'inventory is not canonical jq -cS JSON'
(cd "$success_dir" && sha256sum --check inventory.sha256 >/dev/null) || fail 'inventory hash does not bind JSON bytes'
jq -e '
.schema == "platform-observability-metric-inventory/v1" and
.phase == "target-initial" and .context == "default" and
.api_server == "https://127.0.0.1:6443" and
.prometheus == "observability/observability-core-kube-pr-prometheus" and
.preexisting_verify_only == ["grafana"] and
(.targets | length == 21) and
([.targets[].scrape_pool] == ([.targets[].scrape_pool] | sort)) and
(all(.targets[]; .health == "up" and .last_error == "" and
.metrics == [{"label_names":["__name__","instance","secret_label"],"name":"fixture_metric"}])) and
([.targets[] | select(.scrape_pool=="serviceMonitor/observability/grafana/0") | .provenance] == ["preexisting-verify-only"]) and
([.targets[] | select(.scrape_pool=="serviceMonitor/object-storage/aistor-bucket-usage/0") | .provenance] == ["task6-owned"])
' "$success_dir/inventory.json" >/dev/null || fail 'inventory schema/provenance/content mismatch'
if rg -q 'DO-NOT-LEAK-FIXTURE|private-value|help|query|fragment|exemplar' "$success_dir/inventory.json"; then
fail 'inventory persisted a prohibited value or field'
fi
success_pf_pid="$(head -n 1 "$pf_log")"
if kill -0 "$success_pf_pid" 2>/dev/null; then fail 'port-forward survived success'; fi
oversized_dir="$fixture_root/oversized-response"
mkdir -m 0700 "$oversized_dir"
FAKE_CURL_MODE=oversized_targets
export FAKE_CURL_MODE
expect_reject 'Prometheus response above the byte ceiling rejected' run_capture "$oversized_dir"
unset FAKE_CURL_MODE
[[ -z "$(find "$oversized_dir" -mindepth 1 -maxdepth 1 -print -quit)" ]] || fail 'oversized response produced accepted output'
dropped_live_dir="$fixture_root/dropped-live-response"
mkdir -m 0700 "$dropped_live_dir"
FAKE_CURL_MODE=dropped_blackbox
export FAKE_CURL_MODE
expect_reject 'live dropped blackbox response rejected with exact active set' run_capture "$dropped_live_dir"
unset FAKE_CURL_MODE
[[ -z "$(find "$dropped_live_dir" -mindepth 1 -maxdepth 1 -print -quit)" ]] || fail 'dropped blackbox response produced accepted output'
sigkill_dir="$fixture_root/sigkill"
mkdir -m 0700 "$sigkill_dir"
sigkill_marker="$fixture_root/sigkill-series-started"
sigkill_pf_lines="$(wc -l <"$pf_log")"
sigkill_workdir_lines="$(wc -l <"$pf_workdir_log")"
sigkill_curl_lines="$(wc -l <"$curl_pid_log")"
env PATH="$PATH" FAKE_LOG="$FAKE_LOG" PF_LOG="$PF_LOG" PF_WORKDIR_LOG="$PF_WORKDIR_LOG" \
CURL_PID_LOG="$CURL_PID_LOG" CURL_HANG_MARKER="$sigkill_marker" \
TARGETS_FIXTURE="$TARGETS_FIXTURE" OVERSIZED_TARGETS_FIXTURE="$OVERSIZED_TARGETS_FIXTURE" \
FAKE_CURL_MODE=hang_series bash "$CAPTURE" --execute --phase target-initial --output-dir "$sigkill_dir" \
>/dev/null 2>&1 &
sigkill_capture_pid=$!
for ((attempt=0; attempt<200; attempt++)); do
[[ -e "$sigkill_marker" ]] && break
kill -0 "$sigkill_capture_pid" 2>/dev/null || break
sleep 0.025
done
[[ -e "$sigkill_marker" ]] || fail 'SIGKILL residue fixture did not reach the series request'
sigkill_workdir="$(sed -n "$((sigkill_workdir_lines + 1))p" "$pf_workdir_log")"
sigkill_pf_pid="$(sed -n "$((sigkill_pf_lines + 1))p" "$pf_log")"
sigkill_curl_pid="$(sed -n "$((sigkill_curl_lines + 1))p" "$curl_pid_log")"
[[ "$sigkill_workdir" == /tmp/platform-observability-inventory-capture.* && -d "$sigkill_workdir" && ! -L "$sigkill_workdir" ]] || fail 'SIGKILL fixture work directory was not identified safely'
kill -KILL "$sigkill_capture_pid" 2>/dev/null || true
wait "$sigkill_capture_pid" 2>/dev/null || true
for owned_pid in "$sigkill_curl_pid" "$sigkill_pf_pid"; do
[[ "$owned_pid" =~ ^[0-9]+$ ]] || fail 'SIGKILL fixture lost an owned child PID'
kill -KILL "$owned_pid" 2>/dev/null || true
for ((attempt=0; attempt<40; attempt++)); do
kill -0 "$owned_pid" 2>/dev/null || break
sleep 0.025
done
done
raw_residue="$(find "$sigkill_workdir" -type f \( -name 'targets*.json' -o -name 'rules*.json' -o -name 'metadata*.json' -o -name 'series*.json' \) -print)"
secret_residue=0
if rg -q 'DO-NOT-LEAK-FIXTURE' "$sigkill_workdir"; then secret_residue=1; fi
find "$sigkill_workdir" -depth -delete
[[ -z "$raw_residue" ]] || fail "SIGKILL left raw Prometheus response files: $raw_residue"
[[ "$secret_residue" == 0 ]] || fail 'SIGKILL residue persisted a raw label/help value'
pass_count=$((pass_count + 1))
stubborn_pf_dir="$fixture_root/stubborn-port-forward"
mkdir -m 0700 "$stubborn_pf_dir"
stubborn_lines="$(wc -l <"$pf_log")"
set +e
timeout --preserve-status --signal=TERM --kill-after=0.5s 5s \
env PATH="$PATH" FAKE_LOG="$FAKE_LOG" PF_LOG="$PF_LOG" TARGETS_FIXTURE="$TARGETS_FIXTURE" PF_IGNORE_TERM=1 \
bash "$CAPTURE" --execute --phase target-initial --output-dir "$stubborn_pf_dir" >/dev/null 2>&1
stubborn_rc=$?
set -e
stubborn_pf_pid="$(sed -n "$((stubborn_lines + 1))p" "$pf_log")"
[[ "$stubborn_pf_pid" =~ ^[0-9]+$ ]] || fail 'TERM-ignoring fixture did not start a port-forward'
stubborn_survived_production_cleanup=0
if kill -0 "$stubborn_pf_pid" 2>/dev/null; then
stubborn_survived_production_cleanup=1
kill -KILL "$stubborn_pf_pid" 2>/dev/null || true
for ((attempt=0; attempt<40; attempt++)); do
kill -0 "$stubborn_pf_pid" 2>/dev/null || break
sleep 0.025
done
fi
[[ "$stubborn_rc" == 0 ]] || fail "TERM-ignoring port-forward cleanup exceeded its bound (status $stubborn_rc)"
grep -Fqx "ignored $stubborn_pf_pid TERM" "$pf_log" || fail 'TERM-ignoring fixture did not receive TERM before escalation'
[[ "$stubborn_survived_production_cleanup" == 0 ]] || fail 'TERM-ignoring port-forward survived production cleanup'
pass_count=$((pass_count + 1))
silent_pf_dir="$fixture_root/silent-port-forward"
mkdir -m 0700 "$silent_pf_dir"
PF_NO_ANNOUNCEMENT=1
export PF_NO_ANNOUNCEMENT
expect_pass 'readiness does not depend on port-forward status text' run_capture "$silent_pf_dir"
unset PF_NO_ANNOUNCEMENT
publish_failure_dir="$fixture_root/publish-failure"
mkdir -m 0700 "$publish_failure_dir"
FAIL_SHA_LINK=1
export FAIL_SHA_LINK
expect_reject 'second-file publication failure removes only run-owned output' run_capture "$publish_failure_dir"
unset FAIL_SHA_LINK
[[ -z "$(find "$publish_failure_dir" -mindepth 1 -maxdepth 1 -print -quit)" ]] || fail 'publication failure left a partial inventory'
error_dir="$fixture_root/error"
mkdir -m 0700 "$error_dir"
error_pf_lines="$(wc -l <"$pf_log")"
FAKE_CURL_MODE=error
export FAKE_CURL_MODE
expect_reject 'ordinary API error is sanitized' run_capture "$error_dir"
[[ -z "$(find "$error_dir" -mindepth 1 -maxdepth 1 -print -quit)" ]] || fail 'ordinary error left partial output'
error_pf_pid="$(sed -n "$((error_pf_lines + 1))p" "$pf_log")"
[[ "$error_pf_pid" =~ ^[0-9]+$ ]] || fail 'ordinary error did not start a port-forward'
if kill -0 "$error_pf_pid" 2>/dev/null; then fail 'port-forward survived ordinary error'; fi
unset FAKE_CURL_MODE
for signal in INT TERM HUP; do
signal_dir="$fixture_root/signal-${signal,,}"
mkdir -m 0700 "$signal_dir"
before_lines="$(wc -l <"$pf_log")"
set +e
timeout --preserve-status --signal="$signal" --kill-after=2s 0.3s \
env PATH="$PATH" FAKE_LOG="$FAKE_LOG" PF_LOG="$PF_LOG" TARGETS_FIXTURE="$TARGETS_FIXTURE" FAKE_CURL_MODE=hang \
bash "$CAPTURE" --execute --phase target-initial --output-dir "$signal_dir" >/dev/null 2>&1
signal_rc=$?
set -e
[[ "$signal_rc" != 0 ]] || fail "$signal unexpectedly succeeded"
[[ -z "$(find "$signal_dir" -mindepth 1 -maxdepth 1 -print -quit)" ]] || fail "$signal left partial output"
signal_pf_pid="$(sed -n "$((before_lines + 1))p" "$pf_log")"
[[ "$signal_pf_pid" =~ ^[0-9]+$ ]] || fail "$signal did not start a port-forward"
if kill -0 "$signal_pf_pid" 2>/dev/null; then fail "port-forward survived $signal"; fi
pass_count=$((pass_count + 1))
done
if awk '
/kubectl/ {
line=$0
if (line ~ / <(apply|delete|patch|replace|exec|rollout|scale)>/) exit 1
if (line ~ / <create>/ && line !~ / <auth> <can-i> <create> <pods\/portforward>/) exit 1
}
' "$fake_log"; then :; else fail 'dynamic command trace contains a mutation verb'; fi
# Whole-source proof complements the runtime trace. Removing line boundaries
# prevents a backslash-newline, command prefix, or wrapper alias from hiding a
# mutation verb. The exact RBAC question is the sole create exception.
[[ "$(rg -Fxc " 'create pods/portforward'; do" "$CAPTURE")" == 1 ]] || fail 'port-forward RBAC exception is not pinned exactly once'
mutation_free_source="$(sed "s/'create pods\\/portforward'/'RBAC_PORTFORWARD'/" "$CAPTURE")"
if rg -q '(^|[^[:alnum:]_])(apply|create|delete|patch|replace|exec|rollout|scale)($|[^[:alnum:]_])' <<<"$mutation_free_source"; then
fail 'whole-source proof found a Kubernetes mutation verb'
fi
[[ "$(rg -c '^[[:space:]]*kubectl --request-timeout=' "$CAPTURE")" == 2 ]] || fail 'kubectl invocation count escaped the wrapper/port-forward allowlist'
if rg -q '^[[:space:]]*(alias[[:space:]]+[^=]+=.*kubectl|[A-Za-z_][A-Za-z0-9_]*=.*kubectl)' "$CAPTURE"; then
fail 'kubectl executable alias bypasses the default-deny wrapper'
fi
pass_count=$((pass_count + 1))
printf 'PASS: %d target-initial inventory assertions\n' "$pass_count"