feat(desktop): tenant-wide SAML signing-certificate expiry board - #219
Merged
Conversation
The dev wasm had reached 2.19 GiB, and `rust-lld` cannot write a DWARF custom section that large: `cargo check` passes and the link dies with SIGBUS, which looks nothing like the size problem it is. The tree had been sitting just under the limit, so whichever view got added next would appear to be the thing that broke the build. `debug = "line-tables-only"` takes it to 0.31 GiB. Line tables are the part that survives into a browser panic trace anyway; what's given up is variable inspection in a DWARF-aware wasm debugger. Dev rebuilds also get faster. Deliberately not `strip = "debuginfo"` (what profile.test uses) — that drops the line tables too, and a dev panic pointing at no source line is a bad trade for the last ~0.1 GiB. Supersedes the "profile.dev keeps its debuginfo" note, which is updated in place. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BSW4ReFWuL64BfTkEP74S
The audit's credential rules read an *application's* keyCredentials, but a SAML signing certificate lives on the service principal — so expiring signing certificates were invisible in-app entirely. The first anyone heard of one was Microsoft's 60-day email, which goes to that app's notificationEmailAddresses and, by default, only to the admin who first added it. Security -> "SSO certificates" lists every SAML app's signing certificate, soonest first, on the same AuditDashboard scaffold as the credential board. - `list_saml_sso_service_principals` is ONE server-side filtered scan: `preferredSingleSignOnMode` supports `$filter eq` on the default query surface, and only SAML apps have a signing certificate, so anything wider is waste. Capped at SP_INDEX_MAX over that filtered subset, which no real tenant reaches. - Rows are built by the same `build_rollover` the SSO tab uses, so the board and the per-app panel cannot disagree about whether a replacement is staged. - Two columns carry what the date alone doesn't: whether a replacement is staged (click Activate vs start a rollover), and whether anyone at all is on Entra's 60/30/7-day warnings. The "no replacement staged" facet is the work queue, and the banner counts rows genuinely at risk rather than every row with a date coming up. An expired certificate that still has a staged replacement reads "Auto-promoted" — Entra has already switched. Deliberately NOT a risk-score input. An expiring certificate is an availability risk; risk_score ranks exposure, and points here would push apps up a ranking operators read as "most over-permissioned" for being due routine maintenance. It reuses CredentialStatus + EXPIRY_WARNING_DAYS so "Expiring Soon" means the same on both boards, and an unreadable expiry is Unknown, never Active. Cache busting is wider than it looks: `invalidate_sso_cert_board` fires on Ok from every certificate mutation plus `set_notification_emails` (it flips the "nobody is warned" column) and `set_sso_mode` (it decides board membership). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BSW4ReFWuL64BfTkEP74S
This was referenced Aug 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #218. The audit's credential rules read an application's
keyCredentials, but a SAML signing certificate lives on the service principal — so expiring signing certificates were invisible in-app entirely. The first anyone heard of one was Microsoft's 60-day email, which goes to that app'snotificationEmailAddressesand, by default, only to the admin who originally added the app. This is the list that makes rotation schedulable instead of reactive.Security → "SSO certificates" lists every SAML app's signing certificate, soonest first, on the same
AuditDashboardscaffold as the credential-expiry board (same filters, same badges, same CSV export).preferredSingleSignOnModesupports$filter eqon the default query surface (noConsistencyLevel, no$count), and only SAML apps have a signing certificate — anything wider is waste. Capped atSP_INDEX_MAXover that filtered subset, which no real tenant reaches.build_rolloverthe SSO tab uses, so the board and the per-app panel can't disagree about whether a replacement is staged.Deliberately not a risk-score input
An expiring certificate is an availability risk — sign-in stops on a known date — while
risk_scoreranks exposure. Adding points would push apps up a ranking operators read as "most over-permissioned" because they're due for routine maintenance. It reusesCredentialStatusandEXPIRY_WARNING_DAYSso "Expiring Soon" means the same number of days on both boards, and an unreadable expiry isUnknown, neverActive.Cache busting is wider than it looks
invalidate_sso_cert_boardfires onOkfrom every certificate mutation plusset_notification_emails(it flips the "nobody is warned" column) andset_sso_mode(it decides whether the app is on the board at all). Missing either of those last two leaves the board contradicting the SSO tab for up to the TTL.The build-profile commit (
3deaa47) — please readAdding one more view exposed a latent blocker: the frontend dev wasm had already reached 2.19 GiB, and
rust-lldcan't write a DWARF custom section that large.cargo checkpasses and the link dies withSIGBUS, which looks nothing like the size problem it is. The tree was sitting just under the limit, so whichever view got added next would have appeared to be the thing that broke the build.[profile.dev] debug = "line-tables-only"takes it to 0.31 GiB (verified linking, and dev rebuilds get faster). Line tables are the part that survives into a browser panic trace anyway; what's given up is variable inspection in a DWARF-aware wasm debugger. Deliberately notstrip = "debuginfo"(whatprofile.testuses) — that drops line tables too.This supersedes the existing "scoped to
testso profile.dev keeps its debuginfo" note, which is updated in place rather than left to contradict the new setting. Flagging prominently because it reverses a documented deliberate choice.Test plan
just verify— fmt, clippy, test, web-fmt-check, web-clippy, web-test, web-build all greenUnknown(neverActive), thresholds match the audit's credential rules exactly, and the CSV export guards formula-leading display names while preserving the staged/notified columnsjust web-itestdid NOT run — no chromedriver on this machine. The new dashboard has no behavioural coverage, same gap as feat(desktop): stage SAML signing certificates instead of rotating in place #218$filtershape is covered by unit tests and Microsoft's advanced-query docs, not an integration testFollow-ups
🤖 Generated with Claude Code
https://claude.ai/code/session_017BSW4ReFWuL64BfTkEP74S