kanidm: the provision task reports changed on every converge (unconditional OAuth2 tile-icon upload) #317
Etiketter
Inga etiketter
area/backups
area/ci
area/control-panel
area/identity
area/infra
area/observability
area/payments
area/security
area/storage
area/web
blocked
needs-info
needs-triage
ready-for-implementation
type
bug
type
chore
type
docs
type
epic
type
feature
type
task
wontfix
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Inget förfallodatum satt.
Beroenden
Inga beroenden satta
Referens
bitborg/bitborg-infra#317
Läser in…
Hänvisa till i nytt ärende
Ingen beskrivning angiven.
Ta bort grenen "%!s()"
Borttagning av en gren är permanent. Även om den borttagna grenen kan fortsätta existera en kort tid innan den faktiskt tas bort, kan det INTE ångras i de flesta fall. Vill du fortsätta?
The
kanidmrole reportschanged=1on every converge, forever, on an otherwise fully convergedhost. Found while applying #307 to production on 2026-08-01.
Symptom
Two consecutive
ansible-playbook site.yml --limit gitborg-prod --tags kanidmruns, no changes betweenthem:
The task carries
no_log: true, so the reason is not visible in ordinary output.Cause
Re-running the identical
kanidm-provisioncommand and filtering its log to the mutation verbs thechanged_whenmatches on returns exactly one line, on every run:That is the OAuth2 tile icon (
logo-square.svg) being re-uploaded to theforgejoclient. It appears tobe the one write the tool does not guard behind a comparison —
update_entity_attrs()wraps each attributemutation in
if current_values != values, but the image upload is a separate path with nothing to comparean already-uploaded binary against. Stated as inference from observed behaviour; it was not confirmed
against upstream source.
Exactly one client declares
image_file(forgejo), which matches the single line observed — so this isone unconditional PUT per converge, not a per-client multiplier.
Nothing else is mutated — this is noise, not damage
The filtered log contained that line and nothing else. No group, person, or membership write occurred.
Worth stating explicitly given this repo's history with membership pruning: the tile icon is the entire
mutation, and
--no-auto-removeis unaffected.Why it is still worth fixing
changedon a converged host is the signal for real drift. Pinning it permanently true on this role meansevery future apply shows a change that must be manually dismissed — which is exactly how a genuine
identity-state change gets waved through. It also breaks the "account for every changed task" step of the
apply routine for anyone converging
kanidm.The existing
changed_whencomment already identifies this failure mode and guards against one instance ofit:
Appendingis deliberately excluded because "Matching it would pin changed:true permanently." Theimage
Updatingpins it permanently through a different verb. The history in that same comment records thepredicate having been wrong twice before in the other direction, so it is worth changing carefully rather
than quickly.
Not from #307
Introduced with #287 (tile icon). #307 changed zero icon-related lines — it only surfaced this, because
applying it meant running the role on a converged host and accounting for the result.
Suggested
Two options, neither obviously better:
changed_whenso anUpdatingwhose target ends in/_imagedoes not count, mirroring howAppendingis already excluded. Cheap and local, but adds a second special case to a predicate that hasalready been wrong twice, and it would also mask a genuine icon change.
imageFilein the rendered state when the SVG's checksumdiffers from what is live. Fixes the cause rather than the reporting, but there is no obvious read-back
endpoint for the current image, so this may not be expressible.
Option 1 with a comment recording why is probably right, but the trade-off is worth a moment's thought
rather than a reflex.
Refs #285, #287, #307.