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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/drift-checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,14 @@ jobs:
# helm-ci's `paths:` filter would have skipped entirely.
- name: CLIENT_ENV vocabulary agreement (backend#1729)
run: bash scripts/tests/env-vocabulary-agreement.sh
# The installer's telemetry vocabularies (backend#1907): four closed sets
# whose values are produced elsewhere -- the phases by install-k8s.sh's
# step_header calls, the client states by summary.sh, the script names by
# gen-manifest.sh's FILES array, the error classes by telemetry.sh's own
# classifier. A closed set that has drifted from its producer does not fail
# loudly; it reports `unknown` forever, on exactly the runs somebody added
# the new value for. It lives HERE for the same reason the CLIENT_ENV guard
# does: `Source-of-truth drift` is required, so this can block rather than
# advise. bash only, ~1s.
- name: Telemetry vocabulary agreement (backend#1907)
run: bash scripts/tests/telemetry-vocabulary-agreement.sh
4 changes: 2 additions & 2 deletions .github/workflows/installer-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ jobs:
# below for visibility but don't fail the gate.
shellcheck --severity=error --shell=bash \
scripts/install.sh scripts/install-k8s.sh scripts/gen-manifest.sh scripts/check-facts.sh scripts/check-style.sh scripts/resolve-ingestor-digest.sh scripts/lib/*.sh \
scripts/tests/check-drift.sh scripts/tests/distro-prereqs.sh scripts/tests/e2e-auto-upgrade.sh scripts/tests/e2e-seal-check.sh scripts/tests/e2e-full-seal.sh scripts/tests/e2e-cluster.sh scripts/tests/e2e-journey.sh scripts/tests/e2e-proxy.sh scripts/tests/lib/e2e-common.sh scripts/tests/path-persist.sh scripts/tests/chart-env-vocabulary.sh scripts/tests/env-vocabulary-agreement.sh
scripts/tests/check-drift.sh scripts/tests/distro-prereqs.sh scripts/tests/e2e-auto-upgrade.sh scripts/tests/e2e-seal-check.sh scripts/tests/e2e-full-seal.sh scripts/tests/e2e-cluster.sh scripts/tests/e2e-journey.sh scripts/tests/e2e-proxy.sh scripts/tests/lib/e2e-common.sh scripts/tests/path-persist.sh scripts/tests/chart-env-vocabulary.sh scripts/tests/env-vocabulary-agreement.sh scripts/tests/telemetry-vocabulary-agreement.sh
echo "── shellcheck warnings (advisory, non-blocking) ──"
shellcheck --severity=warning --shell=bash \
scripts/install.sh scripts/install-k8s.sh scripts/gen-manifest.sh scripts/check-facts.sh scripts/check-style.sh scripts/resolve-ingestor-digest.sh scripts/lib/*.sh \
scripts/tests/check-drift.sh scripts/tests/distro-prereqs.sh scripts/tests/e2e-auto-upgrade.sh scripts/tests/e2e-seal-check.sh scripts/tests/e2e-full-seal.sh scripts/tests/e2e-cluster.sh scripts/tests/e2e-journey.sh scripts/tests/e2e-proxy.sh scripts/tests/lib/e2e-common.sh scripts/tests/path-persist.sh scripts/tests/chart-env-vocabulary.sh scripts/tests/env-vocabulary-agreement.sh || true
scripts/tests/check-drift.sh scripts/tests/distro-prereqs.sh scripts/tests/e2e-auto-upgrade.sh scripts/tests/e2e-seal-check.sh scripts/tests/e2e-full-seal.sh scripts/tests/e2e-cluster.sh scripts/tests/e2e-journey.sh scripts/tests/e2e-proxy.sh scripts/tests/lib/e2e-common.sh scripts/tests/path-persist.sh scripts/tests/chart-env-vocabulary.sh scripts/tests/env-vocabulary-agreement.sh scripts/tests/telemetry-vocabulary-agreement.sh || true

- name: Installer manifest is current (supply-chain, R8)
# The bootstrap verifies each sub-script against scripts/manifest.sha256
Expand Down
14 changes: 14 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Deliberate false positives for gitleaks live here. This file is auto-loaded from
# the repo root by tracebloc/.github's code-quality workflow and, unlike the
# baseline, is commit-INDEPENDENT — the right home for a canary fixture the scanner
# keeps re-finding across branch history. (The baseline is only for genuine
# historical exposure tracked for rotation.)
[extend]
useDefault = true

[allowlist]
description = "The telemetry canary tests feed fabricated credentials (hunter2, the joke password) through curl -u / proxy URLs to prove the redaction guards strip them. These are never real secrets, so curl-auth-user hits on `$CANARY:hunter2` across this branch's history are false positives (backend#1907)."
regexTarget = "match"
regexes = [
'''curl -u \$CANARY:hunter2''',
]
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ SHELLCHECK_FILES := \
scripts/tests/lib/e2e-common.sh \
scripts/tests/path-persist.sh \
scripts/tests/chart-env-vocabulary.sh \
scripts/tests/env-vocabulary-agreement.sh
scripts/tests/env-vocabulary-agreement.sh \
scripts/tests/telemetry-vocabulary-agreement.sh

# The bats total, DERIVED — never written down. It moves on most PRs that add a
# test, nothing enforces it, and the help text had drifted from its hardcoded
Expand Down Expand Up @@ -182,6 +183,7 @@ drift:
scripts/check-facts.sh --check
bash scripts/check-style.sh
bash scripts/tests/env-vocabulary-agreement.sh
bash scripts/tests/telemetry-vocabulary-agreement.sh

# digest-drift: the watcher on every mutable label that points at a pinned
# digest (backend#1853). NOT in `check`: it needs the network and a docker
Expand Down
1 change: 1 addition & 0 deletions scripts/gen-manifest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ cd "$REPO_ROOT"
FILES=(
"scripts/install-k8s.sh"
"scripts/lib/common.sh"
"scripts/lib/telemetry.sh"
"scripts/lib/preflight.sh"
"scripts/lib/detect-gpu.sh"
"scripts/lib/gpu-nvidia.sh"
Expand Down
24 changes: 24 additions & 0 deletions scripts/install-k8s.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ LIB_DIR="${SCRIPT_DIR}/lib"

# ── Source modules ───────────────────────────────────────────────────────────
source "${LIB_DIR}/common.sh"
# telemetry.sh (backend#1907) is sourced right after common.sh so the install
# clock starts before any work does, and so common.sh's step_header /
# install_cleanup hooks find their functions. Guarded like the other late
# additions: an older bootstrap (e.g. a not-yet-updated tracebloc.io/i.sh, whose
# FILES list is hand-maintained) may not have fetched it, and an installer that
# aborted because it could not report on itself would be a poor trade.
if [[ -f "${LIB_DIR}/telemetry.sh" ]]; then
source "${LIB_DIR}/telemetry.sh"
fi
source "${LIB_DIR}/preflight.sh"
source "${LIB_DIR}/detect-gpu.sh"
source "${LIB_DIR}/gpu-nvidia.sh"
Expand Down Expand Up @@ -149,6 +158,21 @@ main() {
error "This installer build doesn't include prepare-host (stale bootstrap). Re-run: curl -fsSL https://tracebloc.io/i.sh | bash -s -- prepare-host"
done

# Past this line the run is committed to installing, so it is the one that
# produces an outcome event (backend#1907). Everything above is terminal and
# touches nothing: --help exits 0, --diagnose clears the EXIT trap, and
# prepare-host swaps it for a lightweight reaper. Without this latch, a
# `--help` emitted install.run.succeeded and inflated the denominator of the
# failure rate the ticket exists to produce (Bugbot, client#747).
#
# NOT covered, deliberately: prepare-host. It is a different command with its
# own registry component (§10.1 gives `installer` the components install /
# preflight / upgrade), and reporting it as tracebloc.component=install would
# be mislabelling it rather than measuring it.
if declare -F telemetry_run_started >/dev/null 2>&1; then
telemetry_run_started
fi

# Run-modifying flags (unlike --help/--diagnose, which are terminal). --force /
# --reinstall skips the stop-and-check gate below and re-runs every step. Also
# honored via TRACEBLOC_FORCE_REINSTALL=1 for the curl|bash path (assess.sh
Expand Down
1 change: 1 addition & 0 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ mkdir -p "$TMPDIR/lib"
FILES=(
"scripts/install-k8s.sh"
"scripts/lib/common.sh"
"scripts/lib/telemetry.sh"
"scripts/lib/preflight.sh"
"scripts/lib/detect-gpu.sh"
"scripts/lib/gpu-nvidia.sh"
Expand Down
7 changes: 7 additions & 0 deletions scripts/lib/assess.sh
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,13 @@ _assess_classify() {
# `tracebloc` is somehow still unresolvable, fall back to a short status line so
# a healthy re-run always ends cleanly at exit 0.
_assess_handoff() {
# This exits 0 having run no install step, so the outcome event must say
# `skipped`, not `succeeded` (backend#1907) — otherwise the success count
# grows with every re-run on a machine nothing happened to, and the failure
# rate quietly falls for a reason that has nothing to do with installs.
if declare -F telemetry_run_skipped >/dev/null 2>&1; then
telemetry_run_skipped
fi
success "Already set up on this machine — no need to run the installer again."
export PATH="${HOME}/.local/bin:${PATH}"
if has tracebloc; then
Expand Down
36 changes: 35 additions & 1 deletion scripts/lib/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,21 @@ hint() { echo -e " ${DIM}$*${RESET}"; }
# → " a) Checking your machine". Prints the header + a single trailing blank; the
# blank-line gap BETWEEN steps comes from each step body ending with a blank line
# (main() adds it), matching the run-through's spacing.
step_header() { echo -e " ${TB_HEADING}$1) $2${RESET}"; echo ""; }
#
# It is also where the install's phase clock turns over (backend#1907). Hooking
# THIS rather than adding a telemetry_phase_begin call to each of the six steps
# is the difference between phase timings that are correct by construction and
# phase timings that are correct for the steps somebody remembered — and the
# letters it is keyed on are the ones actually being printed, so nothing can
# drift. Guarded because telemetry.sh may be absent under an older bootstrap
# whose FILES list did not fetch it, and the `|| true` because printing a step
# header must never be able to end an install.
step_header() {
if declare -F telemetry_phase_begin >/dev/null 2>&1; then
telemetry_phase_begin "$1" || true
fi
echo -e " ${TB_HEADING}$1) $2${RESET}"; echo "";
}

# ── Utility ──────────────────────────────────────────────────────────────────
has() { command -v "$1" &>/dev/null; }
Expand Down Expand Up @@ -1095,6 +1109,16 @@ install_cleanup() {
hint "If it keeps failing, re-run with --diagnose and send the bundle to tracebloc support."
fi
fi

# One structured outcome event per install (backend#1907). Emitted LAST, from
# the EXIT trap, so it runs on every path — success, the re-run-required stop,
# Ctrl-C, and the fatal one — which is what §6.5 of the telemetry contract
# requires and what makes a failure RATE computable rather than just a count.
# Everything it reads (CLIENT_STATE, TB_ERR_*, the phase clock) is final by
# this point. Guarded for an older bootstrap that did not fetch telemetry.sh.
if declare -F telemetry_emit_outcome >/dev/null 2>&1; then
telemetry_emit_outcome "$exit_code" || true
fi
Comment thread
cursor[bot] marked this conversation as resolved.
}

# Installer version shown in the banner's title (" · <version>"). The curl|bash
Expand Down Expand Up @@ -1185,6 +1209,16 @@ Advanced configuration (environment variables):
Must be on a LOCAL disk — NFS/CIFS/SMB is rejected (the database
corrupts on network storage). TRACEBLOC_ALLOW_NETWORK_FS=1 overrides.

Usage reporting:
This installer records ONE outcome event per run so we can see failures without
waiting for someone to report them: which step it reached, how long each step
took, the exit code, an error class, your OS and architecture, and the version.
It cannot record your arguments, any path, any file name, your username, your
hostname or your credentials — every field is a number or a value from a fixed
list, so there is nowhere for those to go.
TRACEBLOC_NO_TELEMETRY=1 Turn it off.
DO_NOT_TRACK=1 Also turns it off.

Windows:
irm https://raw.githubusercontent.com/tracebloc/client/main/scripts/install.ps1 | iex

Expand Down
9 changes: 9 additions & 0 deletions scripts/lib/gpu-nvidia.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ install_nvidia_drivers() {
hint "After rebooting, re-run the installer. Driver steps will be skipped."
if [[ -n "${TRACEBLOC_SKIP_REBOOT_PROMPT:-}" ]]; then
log "TRACEBLOC_SKIP_REBOOT_PROMPT set — skipping reboot prompt."
# DECLARE THE HANDOFF, then exit. This is the installer's "complete this step
# and re-run" stop — the drivers went in fine and the machine needs a reboot —
# and telemetry keys `install.run.cancelled` on this marker rather than on the
# number 2, because grep/curl/tar all exit 2 too and one of those escaping
# under `set -e` must be counted as the failure it is. Without this line the
# run books itself as `unexpected_exit_2`, which is the safe direction to be
# wrong in but still wrong. Guarded for a stale bootstrap that did not fetch
# telemetry.sh (same shape as install_cleanup's emit call).
if declare -F telemetry_rerun_handoff >/dev/null 2>&1; then telemetry_rerun_handoff; fi
exit 2
fi
# Read the terminal directly: the main install path is `curl … | bash`, where
Expand Down
5 changes: 4 additions & 1 deletion scripts/lib/summary.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ _log_cluster_status() {
# returns we wait for the client's workloads to actually become Ready and set
# CLIENT_STATE so the summary reports the truth instead of an unconditional
# "installed successfully":
# connected | starting | bad_creds | image_pull | crash
# connected | starting | bad_creds | image_pull | image_pull_ca | crash
# (image_pull_ca is the TLS-inspecting-network case, #424. It was added to
# _diagnose_not_ready and not to this list; backend#1907's vocabulary-agreement
# guard derives the set from the function and caught the omission.)
# Empty until wait_for_client_ready runs — so install_cleanup can distinguish an
# early failure (before the readiness gate, CLIENT_STATE still empty) from a
# reported outcome, and still print the "check the log / safe to re-run" hint.
Expand Down
Loading
Loading