fix(kanidm): bound person auth sessions, and stop the provision task reporting changed every converge #342
Inga granskare
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!342
Läser in…
Hänvisa till i nytt ärende
Ingen beskrivning angiven.
Ta bort grenen "fix/kanidm-role-drift"
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?
Closes #308, closes #317.
#308 — an unset
authsession_expirymeans sessions never expire, not one day. Verified againstthe pinned 1.10.4 source rather than taken on trust: the accessor falls back to
MAXIMUM_AUTH_SESSION_EXPIRY, which isu32::MAX, and the policy fold only ever takes a smallervalue, so a group supplying nothing lowers nothing.
DEFAULT_AUTH_SESSION_EXPIRY(86400) appears onno resolution path — it occurs once, inside a
#[cfg(test)]helper. Unset genuinely meantnow + ~136 years.Two things found that the issue did not state:
downstream SSO could be refreshed indefinitely off one old login. The 16 h refresh-token expiry
bounds nothing on its own.
idm_all_personsis the dyngroup of person accounts, while theprovisioning identity is a service account — so applying this cannot break provisioning or
reconciliation.
Value is 86400 s, with the rejected alternatives recorded in the defaults comment.
privilege_expirywas reconsidered in the same pass and deliberately stays inherited.
#317 — the provision task reported
changedon every converge. Cause confirmed against thepinned provisioning tool rather than inferred: the image upload is a bare
if letwith nocomparison, followed by an unconditional multipart POST. There is no read-back endpoint for a live
image, so the alternative of a conditional upload is not expressible — that settles a trade-off the
issue had left open.
Fixed with a per-line
changed_whenthat excludes only the image re-upload. Per-line is soundbecause the tool logs one verb and target per line. A genuine icon change still surfaces, on the copy
task that owns the file.
Idempotence was not verified with
--check: the task is acommandwith nocheck_mode: false,so a dry run skips it and fabricates
rc: 0. The predicate was instead evaluated verbatim againstcaptured-shape stdout — including the ANSI escapes the tool emits — across eight cases covering the
symptom, real changes alongside it, and the uncoloured form. A real second-converge
changed=0isstill only observable on the next apply.
Verification
ansible-playbook site.yml --syntax-checkclean;ansible-lint0 failures across 191 files, profileproduction; Prettier and markdownlint clean.The kanidm role reported changed=1 on every run of an otherwise fully converged host. The task carries no_log, so the cause was invisible in ordinary output: kanidm-provision re-uploads the OAuth2 tile icon on every run and logs `Updating /v1/oauth2/forgejo/_image`, which the changed_when predicate matched. Confirmed against kanidm-provision v1.3.0 source rather than inferred from behaviour. src/main.rs:312-313 is a bare `if let Some(image_file) = &oauth2.image_file { update_oauth2_image(...) }` with no comparison, and src/client.rs:460-466 logs the line and then POSTs the multipart body unconditionally. There is no read-back endpoint for a live image, so the tool has nothing to compare against and the upload cannot be made conditional from the declared state — which rules out fixing this at the cause and leaves the predicate. So changed_when now filters per line: select the mutation verbs, then reject an `Updating` whose target is an `/_image`. Per line rather than over the whole stdout because log_event is a single `println!("{:>12} {}", verb, message)` (main.rs:30-32), so a verb and its target are always on one line. The suffix is unique — no other log_event ends in `_image`, and `_basic_secret`, the only other unguarded write, is never triggered because basicSecretFile is deliberately never emitted. Masking a genuine icon change is the cost, and it is already covered: the "Stage the OAuth2 tile icon" copy task reports changed whenever the SVG's content differs, so a real change still surfaces — on the task that owns the file. Only the re-upload of an unchanged icon is silenced. Verified by evaluating the predicate directly against captured-shape stdout, including the ANSI escapes log_event emits unconditionally: the icon-only converge now yields false where the previous predicate yielded true, while Creating, Deleting, a group attribute update and an OAuth2 scope-map update all still yield true, alone and alongside the icon line. Not verified by a converge: `--check` skips the command task entirely, so a dry run proves nothing here. Closes #317