SRE Assessment — IaC, DR, Upgrades, SLO/SLA
Assessed 2026-10-29 by four read-only audits (IaC, disaster recovery, upgrades, SLO/SLI) against the live mini and pro clusters, the git trees, and the health-suite reports. CRC was not started for this assessment; everything CRC-side is git-defined or last-known and is labelled as such. Every number on this page is labelled measured (observed live or in a dated record), inferred (derived from measured data), or unproven (no evidence found — a restore that was never drilled is stated as never drilled, not estimated away).
Headlines:
- IaC: 53 of 88 audited units are fully git-defined — 60% (measured for mini/pro, inferred for CRC). Counting content that is in git but hand-delivered, 86% (same basis). The debt is delivery automation and host/DB state, not missing manifests.
- DR: the rebuild-from-git story is drill-proven where exercised (CRC 27m24s, Vault milestones, pro standups). The worst gap is concentrated: the Vault unseal key exists only on the mini — losing that host makes the off-host Vault archives undecryptable. Harbor and StackRox Central, both promoted to pro on 2026-10-29, have no backup at all.
- Upgrades: the most overdue item is not an upgrade but a migration — ingress-nginx v1.15.1 is the final release of a retired project (repo archived 2026-03-24) with a critical unpatched CVE, and it is the mini’s front door. Behind it: Prometheus v2.55.1 (security support ended 2024-12-03), Logstash 8.17.3 (minor EOL 2025-08-12), Vault 2.0.4 (predates the October 2026 security-fix line), and Docker Desktop 4.96.3 on the mini (one release behind a credential-in-logs security fix).
- SLOs: of the proposed SLOs below — 4 MET, 6 MISSED, 5 UNMEASURABLE with today’s measurement. The misses are mostly measurement defects (CRC stopped, inconsistent infra-down gating), but two are real: the LDAP bind matrix at 93.8% and the front-door sweep at 92.9%.
This page supersedes the placement details in the Disaster Recovery chapter (verified 2026-10-24, pre-migration: Harbor, the observability trio, and the logging stack have since moved to pro).
1. IaC coverage
Denominator: 88 units = 48 live Argo CD Applications (measured)
on the mini’s Argo CD (29 destined for the mini, 19 for pro) + ~28
git-defined CRC Applications (inferred count; CRC stopped) + 12 named
non-Argo platform components. At audit time the mini’s Argo CD showed
48 Applications, 47 Synced/Healthy, 1 OutOfSync/Healthy
(pro-harbor) (measured).
| Class | Count | Share |
|---|---|---|
| Fully git-defined (manifest in git and delivered by a live root/ApplicationSet) | 53 | 60% |
| Git-defined content, hand-applied delivery (no live root owns the Application CR) | 23 | 26% |
| Partial / exception (some code; a manual step or DB/host state remains) | 9 of the 12 non-Argo components | — |
| No git home | 3 of the 12 | — |
Exceptions and drift
| # | Item | Risk | State |
|---|---|---|---|
| 1 | Mini’s own argocd/ tree has no live root app; root.yaml points at a personal fork while every live app points at the org repo; the kustomization lists apps that are not live and omits most live tooling-* apps. Bootstrap is a documented manual procedure. | Med | Measured |
| 2 | CRC AlertmanagerConfig conversion-webhook backends (Service + Endpoints + admission cert pair in openshift-monitoring) were hand-made in a 2026-10-25 live repair — not in git; a durable GitOps fix is still owed. The AlertmanagerConfig itself is in git. | Med | Measured (2026-10-25 record); live state unproven, CRC stopped |
| 3 | Classic ARC controller-manager Secret on the mini is hand-applied; its last-applied-configuration annotation embeds the credential payload. This is the burned classic PAT now being replaced by a GitHub App (lab-monorepo#46). | High | Measured |
| 4 | Vault server is a manual Helm install (chart 0.34.1, values in git), not Argo-managed. Its contents are increasingly code: access policies in the lab-monorepo infrastructure/vault-access/ tree; the PKI mount, root CA, and lab-health-issuer role exist (measured, 2026-10-25 record) but have no git definition — treat their creation as bootstrap/manual. | Med | Measured |
| 5 | Harbor LDAP configuration is Harbor DB state, not git. A durable converge script exists on an unmerged branch; until it merges and runs, a pro Docker Desktop reset loses LDAP auth (today it works only because the DB survived the flip). | Med | Measured, fix in flight |
| 6 | Tailscale Serve fronts on pro: 11 fronts, only 2 codified in the registration script; the other 9 exist as documented commands plus check-script expectations. No re-assertion mechanism on the host. | Med | Measured |
| 7 | Docker Desktop VM settings are GUI-set on both hosts, in no repo. Pro sizing is recorded in its README; the mini has no memory/disk keys recorded at all (defaults). | Med | Measured |
| 8 | The pf-ldap port-forward loop on the mini (behind the LDAP front door) is a shell loop with no LaunchAgent and no git home for its script directory. Three sibling pf loops are host-only LaunchAgents, also not in git. | Med | Measured |
| 9 | The Cursor worker Deployment on the mini is labelled git-managed but its last-applied annotation proves hand kubectl apply; no Argo Application; hand-created auth Secret. | Med | Measured |
| 10 | Hand-synced platform Secrets (Vault → cluster) are delivered by git-resident scripts run manually; actuation, not content, is the gap. Rebuild order matters: several Secrets must be synced before Argo can start their pods. | Low–Med | Measured |
| 11 | OpenLDAP seed LDIF is codified (inline in the ldap module, idempotent seed Job) — Low risk; caveat: edits, member adds, and deletions need a live ldapmodify plus a seed update; seed alone does not propagate them. | Low | Measured |
| 12 | cert-manager ClusterIssuer is git; the Cloudflare DNS token lives only in an out-of-band Secret (by design). Argo repo/cluster Secrets are hand-created bootstrap exceptions, documented; the pro cluster Secret is rendered from Vault by script. | Low | Measured |
| — | The mini’s retained Harbor namespace (workloads scaled 0/0, Secrets/PVCs kept) is an intentional rollback snapshot from the 2026-10-29 flip, not drift. Delete only on the owner’s word. | Low | Measured |
Cheapest wins: merge + run the Harbor LDAP script (#5); write one idempotent pro Serve assertion script (#6); LaunchAgent-or-retire pf-ldap (#8).
2. Disaster recovery
RTO/RPO are inferred unless a drill measured them. “Last proven restore” means evidence — a dated drill or restore record — not a belief.
| Service | Backup | Retention | RTO | RPO | Last proven restore |
|---|---|---|---|---|---|
| Vault (mini) | Daily tar of the file-storage tree, two copies (mini + Spark VM), sha256-verified identical | 14 days (dailies); milestone archives never pruned | ~1–3 h (inferred) | 24 h by design (measured) | 2026-10-24 (measured) — archive restored, tree diffed 215/215 identical; full unseal proof rests on the 2026-10-18 drill. Dailies since 10-25 are sha-verified but never restore-drilled |
| ↳ Unseal key | macOS Keychain + a key file — both on the mini only; no off-host escrow, by explicit owner decision 2026-10-24 | — | — | Mini loss = total Vault loss | Unseal from backup proven 2026-10-18 |
| CRC / OpenShift (m4) | Stateless by doctrine; recover.sh rebuilds from git + Vault escrow | Git history | 27m24s best / ~46–55 min typical (measured) | ~0 for desired state | 2026-10-25 (measured) — 3 scripted drills in one day (36/36 live apps — the ~28 git-defined Applications plus ApplicationSet-generated ones — health suite 9/9) |
| Harbor (pro) | None. No backup job, dump, or export found anywhere | None | ~1–2 h to an empty registry (inferred) | Total loss of post-flip content on a pro DD reset | Never — unproven |
| ↳ Mini’s retained Harbor PVCs | Pre-flip DB (~13 MB) + ~1.3 GiB blobs / 55 artifacts, still Bound on the mini | Undefined; no expiry recorded | Rollback to the pre-flip instance only | Protects nothing pushed after the flip; dies with the mini DD disk it would roll back from | n/a |
| StackRox Central (pro) | None. No backup scheduling in the Central CR, no roxctl backup evidence | None | ~1–3 h, rebuild-empty (inferred) | Total for Central-internal state (policies, users, alert history, tokens) | Never — unproven (nothing exists to restore) |
| OpenLDAP (mini) | Seed LDIF in git; credentials of record in Vault | Git history | ~30–60 min (inferred) | Post-seed live changes not captured in git are lost | Rebuild-from-seed never drilled — unproven. Seed fidelity inferred strong (full live directory codified 2026-10-24, bind-verified). One manual seam: the svc-stackrox search ACL lives in cn=config, not the seed |
| Argo CD (mini; manages all 3 clusters) | State is git; first install + root apply are manual seams | Git history | ~1–2 h (inferred) | ~0 for app state | Partially proven (measured): CRC’s bootstrap rebuilt 3× in the 10-25 drills; pro registration is scripted. A cold rebuild of the mini’s own Argo CD has never been drilled |
| Prometheus / Grafana / AlertManager (pro) | No PVCs by construction; dashboards/datasources are git ConfigMaps; TSDB is emptyDir | n/a | <30 min (inferred) | Metrics history + Grafana UI state: total, by design | Rebuild-from-git proven 2026-10-29 (measured) — the trio was stood up fresh on pro in the migration |
| Loki / Tempo / Logstash (pro) | None — by design; Loki retention 72 h in values (measured in git) | 72 h rolling (Loki) | <30 min (inferred) | All stored logs/traces on a DD reset — accepted | Rebuild-from-git proven at standup (measured) |
| MCP / agentops platform (pro) | Stateless services; Secrets sync from Vault by script; images re-pushable from the mini or rebuilt from Dockerfiles | Git history | <1 h (inferred) | Group-request truth lives in the ServiceNow PDI (external, no lab-controlled backup, reclaim cycle applies) + git records | Rebuild proven at the 2026-10-29 pro standup (measured) |
| Memory MCP PostgreSQL (mini) | pg_dump script + restore test exist | None set | ~30 min (inferred) | Stale (measured): newest dump 2026-09-06, ~7 weeks old, single on-host copy, no schedule | Restore test passed once (~Sep 2026, doc record) |
| GitHub repos (the source of truth) | None beyond GitHub itself; local clones are partial and of varying freshness; no mirror or export job | n/a | Days (inferred) | Loss of the org = loss of the canonical source every other row rebuilds from (issues/PRs/Actions secrets are in no clone) | Never — unproven |
| Spark VM | spark-vm-config repo + install script | Git history | Tunnel <1 h (documented); full workspace unproven | Workspace content not in a git repo or a mirror is unprotected | Scoped: the repo restores the CRC-tunnel tooling only — by design, not the whole VM |
| The two Mac hosts | No Time Machine on either — measured (“No destinations configured” on mini and pro; m4 unproven, unreachable with CRC stopped) | — | Host replacement + full cold rebuild | Everything host-local: DD VM disks (all PVCs), the Keychain (the unseal key), Tailscale Serve state, Docker image stores — including the Cursor worker image, for which no build path exists in any repo | Never |
Host-loss blast radius
- Mini dies — the big one. Vault (primary and its unseal key), OpenLDAP (the IdP behind Dex, ACS SSO, Harbor LDAP, CRC OAuth), Argo CD (control plane for all three clusters), the front door + cert-manager, the retained Harbor rollback PVCs, lab-docs. Pro’s workloads keep running but unmanaged and unhealed. The Spark VM’s Vault archive copy survives as sealed ciphertext with no key anywhere off the dead host — every Vault-escrowed rebuild step (CRC pull secret, Argo repo creds, Harbor/Grafana admin, pro cluster token) then fails and must be re-created from original sources, several of which are Vault itself.
- Pro dies — painful, survivable. StackRox Central (ACS dark for
the mini + CRC sensors), Harbor (now the primary registry — a CRC
recover.shrun cannot complete its image pulls without it), pro logging, the observability trio, the agentops platform, pro CI runners. The mini plane (Vault, LDAP, Argo) survives, which is what makes this recoverable. Accepted losses: Harbor and Central return empty; logs/metrics gone by design. Full sequence inferred at ~half a day, dominated by image re-pushes — never run end-to-end as a drill (unproven as a whole); every individual app was proven at standup.
3. Upgrade posture
Current versions are measured live unless noted. “Latest” claims are vendor/endoflife.date figures checked 2026-10-29/30; where a latest could not be verified it says unproven rather than guessing.
| Component | Current | Latest / status | Risk | Mechanism · cadence |
|---|---|---|---|---|
| ingress-nginx (mini front door; CRC git) | chart 4.15.1 / controller v1.15.1 | Final release. Project retired, repo archived 2026-03-24; CVE-2026-42533 (critical NGINX heap overflow, 2026-07-15) is unpatched in 1.15.1; tested only to K8s 1.35 (clusters run 1.36) | Critical | Migration, not a bump — Gateway API / another controller; no drop-in exists. Planned project |
| Prometheus (pro) | v2.55.1 | 3.13 LTS (supported to 2027-07-31); 3.15 newest | High — 2.55 security support ended 2024-12-03 (~23 months unpatched), two majors behind | Manifest image bump; 2.55 is the documented downgrade-safe bridge to 3.x, so the clean-jump window is now. Then LTS annually |
| Logstash (mini + pro) | 8.17.3 | 8.19.x supported to 2027-07-15; 9.x current | High — the 8.17 minor went EOL 2025-08-12 | Manifest image bump to 8.19.x (cheap, same-major); evaluate 9.x quarterly |
| Vault (mini) | 2.0.4 (chart 0.34.1) | 2.2.1 (2026-10-22); four security bulletins fixed in 2.1.2 (2026-10-07) | High — the credential root predates the October security-fix line; highest blast radius per patch in the inventory | Image bump + unseal procedure (standing authorization). Patch on security bulletins; minor quarterly |
| Docker Desktop app | mini 4.96.3, pro 4.97.0 | 4.97.0 (2026-10-26) | High-ish (mini) — 4.97.0 fixes CVE-2026-114409 (third-party API keys/OAuth tokens in cleartext in logs/diagnostics) + a VM-kernel CVE; 4.96.x logs may already hold credentials — sanitise per Docker’s advisory, then update | Manual host update. Weekly check; security releases immediately |
| macOS | mini 27.0.1; pro 15.8.2 | macOS 27 line | High, structural (pro) — the 2018 Intel host is at its inferred hardware ceiling at 15.x; no path forward | Not an upgrade task: hardware-replacement plan for pro; patch while offered |
| OpenLDAP image (mini) | osixia/openldap:1.5.0 | No newer line verified — long-dormant community image (inferred) | Medium-High — every SSO path roots here; unpatched base accumulates silently | Image migration (maintained slapd image), not a bump; quarterly CVE review until then |
| Harbor (pro) | chart 1.19.2 / app v2.15.2 | v2.15.4; v2.15.3 reportedly carried a webhook-SSRF security fix (secondary source — inferred) | Medium — 2 patches behind incl. a security patch; app was OutOfSync/Healthy at audit time | GitOps chart bump. Monthly patch roll |
| Tempo (mini + pro) | chart 1.24.4 / 2.9.0 | 3.1 (GA 2026-09-30) | Medium — a full major behind; 3.1 changes the default block format, so the jump needs a plan | GitOps chart bump ×2. Plan this quarter |
| Grafana (pro) | 11.3.1 | CRC in the same lab runs 13.2.3 (git pin) — internal proof 11.3 is ~2 majors stale | Medium-High (inferred: 11.x out of support) | Manifest image bump; align pro to CRC’s 13.2.3 baseline; quarterly |
| AlertManager (pro) | v0.27.0 | Unproven (~0.28+ expected, not verified) | Medium — 2024-era, bundled with the Prometheus problem | Manifest bump, with the Prometheus work |
| Vector aggregator (CRC, git) | 0.43.1 | 0.61.0 (2026-10-29) | Medium — 18 minors behind; the logging dual-delivery proof re-runs on this build at the next CRC start | GitOps image bump before the next CRC start; quarterly |
| CRC / OpenShift (m4) | 4.22.7 (inferred from git calibration) | 4.22.18 (2026-10-19); 4.22 Full Support ends 2026-12-31, Maintenance to 2027-12-31 | Medium — 11 z-patches behind; lag on a stopped cluster compounds at next start | CRC bundle update on m4 (owner start call). Bump before next start; quarterly |
| Kyverno (mini, pro; CRC git) | chart 3.9.1 / v1.19.1 | v1.19.2 (2026-10-21) | Medium (compat) — 1.19 is tested on K8s 1.33–1.35; both DD clusters run 1.36 (inferred risk) | GitOps chart bump ×3. Monthly; watch the compat matrix |
| StackRox (Central pro; sensors mini/pro; CRC staged) | 4.11.6 | Unproven for the upstream 4.11 line (the lab runs community images; the Red Hat build’s notes are a different lineage) | Medium — cannot be assessed until the upstream latest is pinned | GitOps chart bump ×3. Monthly; first pin down the upstream latest |
| Docker Desktop Kubernetes | mini v1.36.4, pro v1.36.1 | K8s 1.37 current; 1.36 supported | Low — same supported minor; pro 3 patches behind mini | Via Docker Desktop app updates. Monthly; keep patch parity |
| Argo CD (mini) | v3.5.3 | v3.5.6 (2026-10-20) | Low — 3 patches behind, same supported minor | GitOps. Monthly patch roll |
| cert-manager | v1.21.2 | 1.21.3 (2026-10-23) | Low — 1 patch behind | GitOps chart bump. Monthly |
| Tailscale operator / client | operator 1.104.2; clients mini 1.104.1 / pro 1.104.2 | Latest unverified; 1.104.x is an Oct-2026-era line (inferred current) | Low — ≤1 patch skew between hosts | GitOps chart bump / manual host update. Monthly, hosts in lockstep |
| Loki | chart 7.3.0 / 3.6.11 (canary 3.6.12 — skew inside one install) | Later minors unproven | Low | GitOps chart bump ×2. Quarterly; fix the canary tag |
| ARC scale sets (pro) | 0.14.2 | 0.15.0 (2026-10-01) | Low — 1 minor behind | GitOps chart bump ×3. Quarterly |
| ARC classic (mini) | chart 0.23.7 / controller v0.27.6 | Superseded by the scale-set generation (inferred) | Medium — legacy duplicate alongside pro scale sets | Retire, don’t upgrade (drained fallback; removal is GitOps) |
| OpenShift GitOps (CRC) | channel gitops-1.22, automatic (measured in git) | Channel-current by construction | Low-Med — the repo doc still claims channel 1.21 / v1.21.4: doc-vs-git drift that will mislead recovery | OLM subscription. Channel review quarterly; fix the doc |
| OpenShift Logging (CLF) (CRC) | channel stable-6.6, automatic | Latest 6.x unproven | Low | OLM subscription. Review at CRC starts |
| kube-prometheus-stack (CRC, git) | chart 91.8.2 (slim) | Unproven | Low-Med — unverifiable while CRC is stopped | GitOps chart bump. Check at next CRC start |
| Dex | standalone v2.46.0; Argo-bundled v2.45.1 | Unproven | Low — 1-patch internal skew | GitOps chart bump. Quarterly |
| Pushgateway (pro) | v1.9.0 (CRC git pins v1.11.1 — newer than pro) | Unproven | Low | Manifest bump, with the observability sweep |
| m4 macOS / CRC app | Unproven — host unreachable with CRC stopped | — | Unknown | Verify at the next m4 session |
Cross-cutting finding (inferred): everything stood up in October 2026 is within 1–3 patches of latest. Everything inherited from the original mini observability manifests (Prometheus 2.55.1, Grafana 11.3.1, AlertManager 0.27.0, Logstash 8.17.3) was copied to pro unchanged during the migration — the migration modernised placement, not versions.
4. SLOs, error budgets, and the internal SLA
How the SLIs are computed today (measured, from the suite code)
- Auth suite (
report.py): availability = passes / executed runs, infra-down excluded per target. Windows: 394 runs, 2026-10-15 → 2026-10-30 (15 days, not 30 — the “last 30 days” table is currently identical to all-runs). - Service suite (
service_report.py): passes / executed, infra-down and pending excluded; 152 runs over 5 days only. It applies a flat 99% to every check — treated as a real SLO, that would produce 17 simultaneous false “MISSED” verdicts. - Critical inconsistency (measured + inferred): the auth suite gates CRC checks on the tunnel and marks a dead tunnel infra-down (excluded); the service suite calls the CRC API directly and records a refusal as fail. That one difference manufactures most of the 34–65% service numbers while CRC is intentionally stopped. Likewise, in-flight E2E runs graded fail instead of pending inflate the miss.
Definitions adopted by this assessment (proposed)
- Two denominators, always. Conditional SLI (infra-down excluded) answers “does it work when its host is up?”; unconditional SLI (passes / all attempts) answers “could a user actually use it?”. Report both.
- Declared-down exclusion — honestly. A check is excluded only
if the target was in a pre-declared stopped/maintenance state
(a
declared_status.yamlcommitted before or at the stop; a third statusdeclared-down, counted and reported separately). Retroactive edits are not allowed; undeclared down stays a failure in the unconditional SLI. CRC — stopped since 2026-10-26 by owner decision — is exactly this case: CRC SLOs apply only to declared-up windows. If declared-down exceeds 50% of a window, the verdict is UNMEASURABLE, not MET. - 99% everywhere is abandoned — unachievable for browser-through-tunnel checks, too lax for a negative security control, meaningless for a headroom gauge.
- Minimum-n rule: no MET/MISSED verdict on <100 executed runs in the window or <14 days of declared-up data — UNMEASURABLE instead.
SLO table (targets over rolling 30 days)
Current values are measured over the windows that exist today — auth suite 15 days, service suite 5 days — not a full 30. The statuses below are the assessment’s baseline call on that data; rows below the minimum-n rule (front doors n=99, log delivery n=62, oauth-only n≈73, and every service-suite row on its 5-day window) are provisional until a full window accrues, and are marked as called on short windows rather than silently treated as settled.
| Service | SLI source | Current (measured) | Target | Status |
|---|---|---|---|---|
| Harbor — auth/API availability | Auth suite harbor-ldap-login, n=352 | 99.4% | 99.0% | MET |
| Harbor — latency | Same check, composite p95 | 3,968 ms | p95 ≤ 5 s (track the ldap_login step separately, ≤ 2 s) | MET |
| Argo CD (mini) — login | Auth suite mini-argocd-ldap-login, n=369 | 99.5% (exact 99.46%) | 99.0%; latency diagnostic only, p95 ≤ 25 s (now 18.4 s) | MET |
| Vault — availability + unsealed | Service suite vault-availability, n=119 | 99.2% | 99.0%, plus backup freshness ≤ 2 days as its own 100%-of-days target (the check currently allows 14 d) | MET (fragile) — one further in-window failure breaks it |
Front doors (*.rhels.com) | Service suite front-door-sweep, n=99 | 92.9% aggregate | 99.0% per vhost, from two vantages (aggregate kept as a 95% diagnostic) | MISSED — the aggregate also misses its own 95% diagnostic level, and per-vhost data isn’t published yet |
| LDAP — bind matrix | Service suite ldap-bind-matrix, n=113 | 93.8% | 99.0% conditional, reported per leg | MISSED — 7 failures ≈ 6× budget, unexplained; highest-priority investigation |
| MCP roundtrip | Service suite mcp-roundtrip, n=125 | 92.8% | 95.0% conditional on the PDI being available (raw SLI also reported) | MISSED |
| Log delivery (dual-Loki) | Auth suite grafana-cloud-log-delivery, n=62 | 91.9% combined | 95.0% to each sink, reported per sink; declared-up windows only; no latency SLO (poll interval dominates) | MISSED |
| CRC console / Argo auth | Auth suite, n=223 each | 95.1% / 95.1% conditional (unconditional 54.5% — 43% of attempts excluded as infra-down) | 95.0%, declared-up windows only | UNMEASURABLE (provisional: at the line) — no declared-status record exists to build the window from |
| CRC Grafana auth | Auth suite, n=222 | 94.6% conditional | 95.0%, declared-up only | UNMEASURABLE (provisional: missed) |
| OAuth-only posture checks | Auth suite, n=73/74 | 86.3% / 86.5% | Split out as security controls: 100%, reported as pass/fail events, never averaged | MISSED / investigate — the SLI conflates posture regressions with login flakiness; cannot tell if any failure was a real breach |
| Wrong-password rejection | Auth suite console-wrong-password, n=223 | 97.8% (5 failures) | 100% — zero tolerance; any failure is a security incident, not budget spend | MISSED — treat as security events |
| E2E pipeline / CI runners | Service suite e2e-* stages | Stage numbers 34–83% — not service availability (cross-correlated stopped-era artefacts; no run-level composite exists) | 90% of triggered runs fully succeed + p95 trigger→complete ≤ 90 min (declared-up only); runners: 95% of jobs start ≤ 5 min | UNMEASURABLE — no run-level SLI; runner queue time is not recorded at all |
| Cert headroom | Service suite cert-expiry | Binary pass/fail only (39.8%, CRC-conflated) | Not an availability SLO: 100% of days with min headroom ≥ 21 days; alert at 30 days | UNMEASURABLE — the days-left value exists in check detail but is never aggregated |
| Grafana / Docs / Prometheus / Alerts (per-vhost) | Front-door sweep aggregate only | — | 99.0% front-door availability via the per-vhost SLI | UNMEASURABLE — no per-vhost or login checks exist |
Latency SLOs explicitly not proposed: all CRC browser flows
(median 18–41 s is tunnel + Chromium + OAuth settle waits — a latency
SLO there would optimise the test harness), the LDAP matrix median
(12.6 s is SSH/kubectl exec overhead), the sweep median (a sum of
sequential probes), E2E stage “durations” (observer runtime), and the
Vault median (SSH overhead). The only user-meaningful latency numbers
today are the Harbor API and, loosely, MCP roundtrip (2.6 s median,
PDI-tainted).
Error budgets and burn policy (proposed)
30 days = 43,200 minutes; for an hourly synthetic, the probe count is the operative budget.
| SLO level | Budget / 30 d | ≈ failed hourly probes | Consumed by current data (inferred) |
|---|---|---|---|
| 99.0% (Harbor, mini-Argo, Vault, LDAP, front doors) | 432 min (7.2 h) | ~7 of 720 | Harbor ~29% · mini-Argo ~29% · Vault ~84% of its in-window allowance · LDAP ~620% — exhausted ~6× · front doors ~700% — exhausted |
| 95.0% (CRC auth, MCP, log delivery) | 2,160 min (36 h) | ~36 | CRC console/Argo at the line · Grafana over · MCP over (7.2% errors) · log delivery over (8.1%) |
| 90.0% (E2E pipeline) | 4,320 min (72 h) | per-run | Unmeasurable |
| Trigger | Action |
|---|---|
| Any negative-auth-control failure; Vault sealed; cert headroom < 21 d | Immediate incident, bypasses budget math: GitHub issue via the alert bridge + owner notification the same day |
| Fast burn: > 25% of the 30 d budget in 7 days, or 3 consecutive failed runs | Alert via AlertManager → bridge → GitHub issue (the lab’s de-facto paging). Owner triages within 24 h; no new feature work on that service until triaged |
| 50% of budget consumed (≥ 7 days left in window) | Reliability work takes priority for that service; the next change must be a fix or carry an explicit owner waiver on the issue |
| 100% consumed | Change freeze on that service (reliability fixes and rollbacks only) + a short post-mortem note (cause, declared-vs-undeclared split, budget reset date); owner explicitly lifts the freeze. No spillover to unrelated services |
| Budget exhausted solely by infra-down misclassification | Fix the measurement first, annotate the window measurement-invalid; never retroactively rewrite history or silently reset the budget |
| Declared-down periods | Never consume budget, never trigger burn — but declared-down days are reported next to every SLI |
Internal SLA (proposed) — one-operator lab
RHELS Lab — Internal Service Commitments (draft, not a contract)
Who this covers. The lab owner (operator) commits to the app/platform teams and agents who build on the lab, and to the owner’s own projects. There is one operator. There is no on-call rotation, no NOC, and no vendor behind this.
What is committed (rolling 30 days, declared-up windows): Vault available & unsealed 99%; Harbor registry auth/API 99%; mini Argo CD login 99%;
*.rhels.comfront doors 99% per vhost; LDAP binds 99%. CRC/OpenShift platform, when declared up: console/Argo/Grafana auth 95%. MCP roundtrip 95% (PDI-dependent); dual-Loki log delivery 95%. Security controls (wrong-password rejection, oauth-only posture, signed-image policy) are not percentage commitments: a failure is an incident, full stop.Support reality. Best-effort during the operator’s waking hours, America/Chicago. Alerts route to GitHub issues via the alert bridge — notification, not a guaranteed page. Target response: same day for Vault/Harbor/LDAP/front-door incidents; next 1–2 days for CRC, MCP, pipeline, and log-delivery issues. No response-time guarantee outside waking hours, weekends, or the operator’s absence.
Exclusions — these do not count against the commitments:
- Declared stops & maintenance — e.g. CRC stopped by owner decision since 2026-10-26; the chess-time CRC auto-stop (Mon/Wed evenings); any stop declared in advance in the lab repo.
- Host hardware / host OS — host failure, sleep, or power; Docker Desktop failure on the host.
- Connectivity the lab doesn’t control — home ISP (including its inbound 80/443 block), Tailscale/tailnet, the egress proxy, power at the house.
- External services — ServiceNow PDI (incl. its sleep/wake), Grafana Cloud, Let’s Encrypt, GitHub Actions availability.
- Tenant/demo workloads — the app1001-series and namespace-request experiments; reported, not masked, and not covered.
What “support” does not include. Data recovery beyond the existing Vault backup regime; guaranteed E2E pipeline turnaround; any availability claim for a service with no SLI.
Review. SLOs, budgets, and this SLA are reviewed when (a) a budget is exhausted, (b) CRC’s declared status changes, or (c) 30 days of clean declared-up data exists — whichever comes first. Changes are owner-approved and committed to the lab repo.
CI runners, as a commitment: best-effort with queue transparency — the proposed 95%-of-jobs-start-≤5-min objective becomes a commitment only once queue wait is actually measured (today it is not recorded at all).
Measurement gaps — cheapest fix first
- Declared-status record (
declared_status.yaml+ a third status in both suites). Blocks every honest CRC verdict. Do first — it unblocks half the table. - Consistent infra-down gating in the service suite — preflight the CRC API once, as the auth suite preflights the tunnel.
- E2E run-level composite SLI — join stages by the run id already on disk; in-flight runs count pending until the 90-minute timeout (this also fixes the known observer defect where mid-cycle runs grade FAIL).
- Harbor push/pull success from real CI — report job-level step conclusions from the Actions API; login at 99.4% does not prove pulls work.
- CI runner queue wait — the Actions API timestamps on runs the trigger already dispatches.
- Cert headroom as a number — the check already fetches every cert’s expiry; emit days-left and aggregate min/p25. Report-side only.
- Front-door second vantage + per-vhost rows — the probe code already exists; run it from a second host.
- Real LDAP bind latency (on-mini) — time the bind calls inside the existing on-mini script instead of timing the SSH around them.
- Per-sink log-delivery SLI + delivery lag — the check already queries both Lokis separately; record per-sink results.
- Vault API latency + backup age as separate SLIs — emit backup age in days; tighten the freshness threshold from 14 d to 2 d.
- Argo census split (mini vs CRC) — the data is already fetched per cluster; mini GitOps health currently has no clean trend.
- Step-level p95 for Harbor
ldap_login— the composite p95 is dominated by the deliberate wrong-password step (2 s median), masking real login-latency drift.
5. Where the fixes live
The gaps above are tracked as a checklist backlog in
rhels/lab-monorepo (label spark): Vault unseal-key escrow
decision, Harbor + StackRox backups, the ingress-nginx migration,
Prometheus 3.13 LTS, Logstash 8.19.x, the Vault security line,
Docker Desktop 4.97.0 on the mini, the mini root app + fork fix, the
pro Serve assertion script, pf-ldap, the mini-Argo and LDAP-seed
rebuild drills, Vault daily restore drills, a GitHub mirror/export,
classic-ARC retirement, the OpenLDAP image migration, the Vector bump
before the next CRC start, observability version alignment on pro,
the stale DR/CRC-GitOps docs, and the twelve measurement gaps.
Nothing on this page was changed silently — assessment and
definitions only.