feat(ops-agent): drift-detector ziet repo-vs-runtime, en die drift is nu op te heffen #140

Merged
janpeter merged 2 commits from feat/drift-repo-runtime-layer into main 2026-08-02 22:25:16 +02:00
Owner

De detector vergeleek runtime-baseline ↔ live /etc/ops-agent en las de repo-kopie nooit. no drift bewees dus alleen runtime == live.

Die blinde vlek beet echt: de build-laag uit PR #135 zat wél in de repo en niet in het runtime-script, en de check meldde no drift terwijl hij de env-knop domweg negeerde.

Eerst gemeten, toen pas gebouwd

De opdracht vroeg uit te zoeken of er überhaupt iets de runtime-baseline vanuit de repo synct. Antwoord: nee.

kandidaat uitkomst
setup.sh alleen een comment, geen sync
systemd-unit leest de baseline als ExecStart-argument
script in de repo nul treffers
command-key / flow geen
cron (root + user) geen
docs/ niet gedocumenteerd

Ook het drift-script zélf wordt door niets geïnstalleerd. De .bak.*-bestanden naast de baseline zijn de vingerafdrukken van handmatige syncs — workerfix-20260711, smokeretry-20260714, readyprobe-20260727 en drie van vandaag.

En de unit-header belooft letterlijk iets wat niet bestaat:

# repo under deploy/ops-agent/ is the version-controlled source; it is synced to
# the runtime path on apply:

Alarmeren op een toestand zonder knop levert een detector op die iets meldt wat niemand kan wegnemen. Daarom twee delen.

1. apply-drift-runtime.sh — de sync bestaanbaar maken

Kopieert script + baseline vanuit de repo naar het runtime-pad, en leidt dat pad af uit de ExecStart van de unit zodat er geen tweede plek is waar het staat. Idempotent, root-only. Laat de .bak.*-historie staan: bewijsmateriaal, geen rommel.

2. De derde laag in de detector

Geen nieuwe env-knop en geen vierde pad — het repo-pad wordt afgeleid uit OPS_AGENT_SRC_DIR (<repo>/ops-agent), dat de build-laag toch al zet.

Referentie-revisie: de werkboom, niet origin/main. Reden: apply-drift-runtime.sh kopieert uit de werkboom. Zou de detector tegen origin/main meten, dan meldt hij drift die de remedie niet kan opheffen. De prijs is dat een achterlopende of vuile checkout een schone meting kan geven — daarom rapporteert de detector nu altijd waartegen hij vergeleken heeft:

laag repo<->runtime: vergeleken met …/deploy/ops-agent/baseline
  (feat/drift-repo-runtime-layer@7de209a, VUIL, geen upstream)

Bewijzen

Vuil in beide richtingen, en weer schoon:

runtime-only bestand   | repo:flows/zz-runtime-only.yml | in runtime-baseline, niet in repo-baseline | exit 1
repo-only bestand      | repo:flows/zz-repo-only.yml    | in repo-baseline, niet in runtime-baseline | exit 1
inhoudelijk verschil   | repo:commands.yml              | repo-baseline wijkt af van runtime-baseline | exit 1
hersteld               | no drift                                                                    | exit 0

Fail closed, benoemde reden:

ERROR: OPS_AGENT_SRC_DIR set but not a directory: /srv/bestaat-niet/ops-agent          -> exit 2
ERROR: repo-baseline niet gevonden: …/halfrepo/deploy/ops-agent/baseline
       (afgeleid uit OPS_AGENT_SRC_DIR)                                                -> exit 2

De remedie heft op wat de detector meldt:

vóór apply:  1 config, 1 repo-vs-runtime, 0 installed-build   exit 1
apply:       klaar — runtime komt nu overeen met de repo
ná apply:    no drift                                          exit 0

De laag wordt echt uitgevoerd (niet stilzwijgend overgeslagen zoals OPS_AGENT_SRC_DIR maandenlang): via de systemd-unit staat de laag repo<->runtime:-regel in het journal, en bij een ongezette knop staat er expliciet OVERGESLAGEN.

Twee testfouten van mij, voor de volledigheid

Mijn eerste fail-closed-test gebruikte chmod 000 — zinloos, want de check draait als root en root omzeilt mode-bits. En mijn eerste remedie-test voegde een bestand toe dat alleen in de repo bestond; na de apply stond dat in runtime maar niet live, dus terecht laag-2-drift. Beide overgedaan met een opzet die de bedoelde tak wél raakt.

De detector vergeleek runtime-baseline ↔ live `/etc/ops-agent` en las de repo-kopie **nooit**. `no drift` bewees dus alleen *runtime == live*. Die blinde vlek beet echt: de build-laag uit PR #135 zat wél in de repo en niet in het runtime-script, en de check meldde `no drift` terwijl hij de env-knop domweg negeerde. ## Eerst gemeten, toen pas gebouwd De opdracht vroeg uit te zoeken of er überhaupt iets de runtime-baseline vanuit de repo synct. **Antwoord: nee.** | kandidaat | uitkomst | |---|---| | `setup.sh` | alleen een comment, geen sync | | systemd-unit | **leest** de baseline als ExecStart-argument | | script in de repo | nul treffers | | command-key / flow | geen | | cron (root + user) | geen | | `docs/` | niet gedocumenteerd | Ook het drift-script zélf wordt door niets geïnstalleerd. De `.bak.*`-bestanden naast de baseline zijn de vingerafdrukken van handmatige syncs — `workerfix-20260711`, `smokeretry-20260714`, `readyprobe-20260727` en drie van vandaag. En de unit-header belooft letterlijk iets wat niet bestaat: ``` # repo under deploy/ops-agent/ is the version-controlled source; it is synced to # the runtime path on apply: ``` Alarmeren op een toestand zonder knop levert een detector op die iets meldt wat niemand kan wegnemen. Daarom twee delen. ## 1. `apply-drift-runtime.sh` — de sync bestaanbaar maken Kopieert script + baseline vanuit de repo naar het runtime-pad, en **leidt dat pad af uit de `ExecStart` van de unit** zodat er geen tweede plek is waar het staat. Idempotent, root-only. Laat de `.bak.*`-historie staan: bewijsmateriaal, geen rommel. ## 2. De derde laag in de detector Geen nieuwe env-knop en geen vierde pad — het repo-pad wordt afgeleid uit `OPS_AGENT_SRC_DIR` (`<repo>/ops-agent`), dat de build-laag toch al zet. **Referentie-revisie: de werkboom, niet `origin/main`.** Reden: `apply-drift-runtime.sh` kopieert uit de werkboom. Zou de detector tegen `origin/main` meten, dan meldt hij drift die de remedie niet kan opheffen. De prijs is dat een achterlopende of vuile checkout een schone meting kan geven — daarom rapporteert de detector nu **altijd** waartegen hij vergeleken heeft: ``` laag repo<->runtime: vergeleken met …/deploy/ops-agent/baseline (feat/drift-repo-runtime-layer@7de209a, VUIL, geen upstream) ``` ## Bewijzen **Vuil in beide richtingen, en weer schoon:** ``` runtime-only bestand | repo:flows/zz-runtime-only.yml | in runtime-baseline, niet in repo-baseline | exit 1 repo-only bestand | repo:flows/zz-repo-only.yml | in repo-baseline, niet in runtime-baseline | exit 1 inhoudelijk verschil | repo:commands.yml | repo-baseline wijkt af van runtime-baseline | exit 1 hersteld | no drift | exit 0 ``` **Fail closed, benoemde reden:** ``` ERROR: OPS_AGENT_SRC_DIR set but not a directory: /srv/bestaat-niet/ops-agent -> exit 2 ERROR: repo-baseline niet gevonden: …/halfrepo/deploy/ops-agent/baseline (afgeleid uit OPS_AGENT_SRC_DIR) -> exit 2 ``` **De remedie heft op wat de detector meldt:** ``` vóór apply: 1 config, 1 repo-vs-runtime, 0 installed-build exit 1 apply: klaar — runtime komt nu overeen met de repo ná apply: no drift exit 0 ``` **De laag wordt echt uitgevoerd** (niet stilzwijgend overgeslagen zoals `OPS_AGENT_SRC_DIR` maandenlang): via de systemd-unit staat de `laag repo<->runtime:`-regel in het journal, en bij een ongezette knop staat er expliciet `OVERGESLAGEN`. ## Twee testfouten van mij, voor de volledigheid Mijn eerste fail-closed-test gebruikte `chmod 000` — zinloos, want de check draait als root en root omzeilt mode-bits. En mijn eerste remedie-test voegde een bestand toe dat alleen in de repo bestond; na de apply stond dat in runtime maar niet live, dus terecht laag-2-drift. Beide overgedaan met een opzet die de bedoelde tak wél raakt.
feat(ops-agent): drift-detector ziet repo-vs-runtime, en die drift is nu op te heffen
Some checks failed
CI / Ops-agent checks (pull_request) Has been cancelled
CI / Deploy artifact checks (pull_request) Has been cancelled
CI / Docker image build (pull_request) Has been cancelled
CI / Root app checks (pull_request) Has been cancelled
02d03630d0
De detector vergeleek runtime-baseline met live /etc/ops-agent en las de repo-kopie
nooit. `no drift` bewees dus alleen runtime == live. Die blinde vlek beet echt: de
build-laag uit PR #135 zat wel in de repo en niet in het runtime-script, en de check
meldde vrolijk `no drift` terwijl hij de env-knop negeerde.

EERST GEMETEN, TOEN PAS GEBOUWD. De opdracht vroeg uit te zoeken of er uberhaupt iets
de runtime-baseline vanuit de repo synct. Antwoord: nee. Niet in setup.sh, geen unit,
geen script, geen command-key, geen cron, niet gedocumenteerd. Ook het drift-script
zelf wordt door niets geinstalleerd. De .bak.*-bestanden naast de baseline zijn de
vingerafdrukken van handmatige syncs — drie ervan van vandaag.

Erger: de unit-header belooft "the repo under deploy/ops-agent/ is the
version-controlled source; it is synced to the runtime path on apply". Die apply
bestond alleen als zin. Alarmeren op een toestand zonder knop zou een detector
opleveren die iets meldt wat niemand kan wegnemen, dus:

1. apply-drift-runtime.sh maakt de sync bestaanbaar. Kopieert script + baseline vanuit
   de repo naar het runtime-pad, en leidt dat pad af uit de ExecStart van de unit zodat
   er geen tweede plek is waar het staat. Idempotent, root-only. Laat de .bak.*-historie
   staan: die is bewijsmateriaal, geen rommel.
2. De detector krijgt laag 1. Geen nieuwe env-knop en geen vierde pad — het repo-pad
   wordt afgeleid uit OPS_AGENT_SRC_DIR (= <repo>/ops-agent), dat de build-laag al zet.

REFERENTIE-REVISIE: vergeleken wordt tegen de WERKBOOM van de checkout, niet tegen
origin/main. Reden: apply-drift-runtime.sh kopieert uit de werkboom. Zou de detector
tegen origin/main meten, dan meldt hij drift die de remedie niet kan opheffen — precies
de incoherentie die deze taak wilde vermijden. De prijs is dat een achterlopende of
vuile checkout een schone meting kan opleveren, en daarom rapporteert de detector nu
altijd waartegen hij vergeleken heeft: branch@sha, schoon/VUIL, en vooruit/ACHTER op
upstream. "Runtime komt overeen met een checkout die 2 commits achterloopt" is een
bevinding, geen schone uitkomst.

FAIL CLOSED: een onvindbare of onvolledige checkout geeft exit 2 met benoemde reden,
nooit "overslaan en schoon melden".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
s4m-codex-reviewer requested changes 2026-08-02 21:35:53 +02:00
Dismissed
s4m-codex-reviewer left a comment

Verdict: REQUEST_CHANGES

geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden.

Findings

  • ERRORdeploy/ops-agent/scripts/apply-drift-runtime.sh:57: het apply-script kopieert repo-flows naar $RUNTIME_BASELINE/flows, maar verwijdert geen runtime-flowfiles die niet meer in de repo-baseline bestaan. De aangepaste detector meldt zulke extra runtimefiles expliciet als repo:flows/<name> ... in runtime-baseline, niet in repo-baseline, waardoor de voorgeschreven herstelactie apply-drift-runtime.sh die drift niet kan opheffen. Dit maakt de nieuwe repo-vs-runtime laag praktisch niet idempotent voor delete/rename-cases. Laat het script de vergeleken flowset exact synchroniseren, of verwijder minimaal runtime flows/*.yml die geen corresponderende repo-flow meer hebben zonder de .bak.* historie naast de baseline te wissen.
# Verdict: REQUEST_CHANGES geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden. ## Findings - **ERROR** — `deploy/ops-agent/scripts/apply-drift-runtime.sh:57`: het apply-script kopieert repo-flows naar `$RUNTIME_BASELINE/flows`, maar verwijdert geen runtime-flowfiles die niet meer in de repo-baseline bestaan. De aangepaste detector meldt zulke extra runtimefiles expliciet als `repo:flows/<name> ... in runtime-baseline, niet in repo-baseline`, waardoor de voorgeschreven herstelactie `apply-drift-runtime.sh` die drift niet kan opheffen. Dit maakt de nieuwe repo-vs-runtime laag praktisch niet idempotent voor delete/rename-cases. Laat het script de vergeleken flowset exact synchroniseren, of verwijder minimaal runtime `flows/*.yml` die geen corresponderende repo-flow meer hebben zonder de `.bak.*` historie naast de baseline te wissen.
fix(ops-agent): laag 1 vergelijkt ook het script, niet alleen de baseline
All checks were successful
CI / Root app checks (pull_request) Successful in 6m1s
CI / Ops-agent checks (pull_request) Successful in 16s
CI / Deploy artifact checks (pull_request) Successful in 34s
CI / Docker image build (pull_request) Successful in 1m21s
bd489543d8
Gat in mijn eigen implementatie, gevonden door de eerste run op main. Laag 1
vergeleek alleen de baselines — terwijl het geval dat deze hele laag motiveerde
juist een SCRIPT-divergentie was: de build-laag uit PR #135 zat in de repo-versie
van check-ops-agent-drift.sh en niet in de runtime-versie, en de check negeerde
daardoor maandenlang OPS_AGENT_SRC_DIR.

Een laag die alleen baselines toetst had precies dat gemist. apply-drift-runtime.sh
synct script en baseline allebei, dus allebei horen ze getoetst.

Bewezen: runtime-script bewust verouderd ->
  | repo:check-ops-agent-drift.sh | 1 | runtime-script wijkt af van de repo-versie |
  exit 1
apply-drift-runtime.sh -> no drift, exit 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
s4m-codex-reviewer left a comment

Verdict: REQUEST_CHANGES

Geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden.

Findings

  • errordeploy/ops-agent/scripts/apply-drift-runtime.sh:58 — De detector meldt extra runtime-flowbestanden als repo-vs-runtime drift (in runtime-baseline, niet in repo-baseline), maar de herstelknop kopieert alleen flowbestanden die in de repo-baseline bestaan en verwijdert geen runtime-only flowbestanden. Daardoor blijft deze door de PR nieuw geintroduceerde driftcategorie na apply-drift-runtime.sh bestaan, terwijl de reviewtekst expliciet belooft dat dit script de repo-vs-runtime drift opheft. Maak de apply-stap symmetrisch voor de set bestanden die de detector vergelijkt, bijvoorbeeld door runtime-only flows/*.yml gecontroleerd te verwijderen of de baseline-directory atomisch uit de repo te reconstrueren zonder ongecontroleerde .bak.*-historie te verliezen buiten de vergeleken set.
# Verdict: REQUEST_CHANGES Geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden. ## Findings - **error** — `deploy/ops-agent/scripts/apply-drift-runtime.sh:58` — De detector meldt extra runtime-flowbestanden als repo-vs-runtime drift (`in runtime-baseline, niet in repo-baseline`), maar de herstelknop kopieert alleen flowbestanden die in de repo-baseline bestaan en verwijdert geen runtime-only flowbestanden. Daardoor blijft deze door de PR nieuw geintroduceerde driftcategorie na `apply-drift-runtime.sh` bestaan, terwijl de reviewtekst expliciet belooft dat dit script de repo-vs-runtime drift opheft. Maak de apply-stap symmetrisch voor de set bestanden die de detector vergelijkt, bijvoorbeeld door runtime-only `flows/*.yml` gecontroleerd te verwijderen of de baseline-directory atomisch uit de repo te reconstrueren zonder ongecontroleerde `.bak.*`-historie te verliezen buiten de vergeleken set.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
janpeter/Ops-dashboard!140
No description provided.