Repository navigation
Sign-out audit rows record the client address, and the no-local-Administrator WARNING keeps every name (BACKLOG #3339, #3282) - #2435
Conversation
AuthService.logout takes an optional client keyword and records it on the auth.logout audit row. POST /auth/logout and /ui/logout both pass client_ip(request), the extractor the other audited auth routes use. Closing step 2 was already met by PR 2384 (BACKLOG #3029): a sign-out that revokes nothing writes its own recorded detail.outcome, nothing_to_revoke. Unchanged here. Not fixed: a console sign-out that loses a rotation race keeps a NULL actor. The rotated row no longer answers to the presented hash, so a lookup by it finds nothing; naming the owner needs the store to keep a re-keyed session's prior hash, on three backends. Tests read the row back for each route (actor, client, outcome), with a pinned peer. Control: /ui/logout with a cookie naming no session records nothing_to_revoke, no actor, and the address. The web console seam digest moved (5d9c162790077dfc to 499c326be7a5a50b) because logout's signature changed.
…iew round 1 (BACKLOG #3339) - With no actor, logout reads the session through _load_session before supersede_session and names that row's owner. A console sign-out that loses a rotation race now names the owner, as POST /auth/logout's own dependency read does (engine PR 2384 open finding 3). The owner comes from a row whose seal verified, not from the blanked row the revoke returns. A cookie re-keyed before the request still names no actor. - client is a required keyword, as on revoke_own_session, so a new sign-out caller cannot omit it silently. Test call sites pass it. - The route tests sign in and sign out from different addresses, so the row cannot pass by recording the session's login address. - New service tests: client reaches the row on both outcomes, and the race test, red on the prior logout (its injection never fires) and red when the owner is taken only from an ended row. - Changelog drops its completeness claim; the seam digest is re-derived (now 1f2d208818510f18).
The round 1 pre-read went through _load_session, the one sanctioned session reader. It ends and reports a row whose seal fails, so the revoke then found nothing and the row said nothing_to_revoke with no actor for a session this call ended. It also put a failure point ahead of the revoke. A side-effect-free read would need a second get_session reader, which tests/test_session_seal.py forbids. logout attributes the owner of the row the revoke ended again, as PR 2384 left it. A console sign-out that loses a rotation race keeps a NULL actor; the docstring and changelog say so, and why. The POST /auth/logout race test now signs in from another address, so its client assertion is the sign-out's own address.
The start WARNING from report_administrators_needing_an_outside_service put the usernames right after "no usable password:". The shipped CredentialScrubFilter reads "password: <value>" as a credential and masked the first name. The list now follows "Accounts that need one:", ahead of the word "password". logging_setup.py and secretscrub.py are unchanged. Test: every name survives the filter chain every engine handler carries (filtered_sink, the real _install_phi_filters), not caplog. A control sends the old wording through the same chain and loses the first name. The test is red on the prior wording.
…OG #3339) - packaging/messagefoundry-webconsole/CHANGELOG.md records the console change and the seam move, as changelog.d/README.md requires. - The logout docstring no longer says a NULL client means no request: client_ip can find no address on a real request. The race residual cites engine PR 2384 open finding 3 rather than this item. - The /ui/logout control test says it pins still-open behaviour (PR 2384 open finding 6, held by vault BACKLOG #3749).
…(BACKLOG #3282) The WARNING lost its first name from the day it was added, so this is not a regression undone. A name that looks like a credential label or a date can still be rewritten by the log filters; the audit row holds the complete list. Proposed PR title: Sign-out audit rows record the client address, and the no-local-Administrator WARNING keeps every name (BACKLOG #3339, #3282) Proposed banner #3339: BUILT, pending merge. POST /auth/logout and /ui/logout pass client_ip, and AuthService.logout records it on the auth.logout row through a required client keyword. Tests read the row back for each route (actor, client, outcome), signing in and out from different addresses; a control signs out with a cookie naming no session. Closing step 2 was already met by engine PR 2384: a sign-out that revokes nothing records detail.outcome nothing_to_revoke on the same action. Open: a console sign-out that loses a rotation race keeps a NULL actor (PR 2384 finding 3); closing step 4, the ASVS 16.2.1 re-read, is vault record work. Web console seam digest moved to 1f2d208818510f18. Proposed banner #3282: BUILT, pending merge. The start WARNING lists the accounts after "Accounts that need one:", ahead of the word "password", so the shipped CredentialScrubFilter no longer masks the first name. A test sends the real WARNING through the shipped handler filter chain and finds every name; a control shows the old wording loses one. logging_setup.py and secretscrub.py are unchanged.
|
QA line, BUILDER.md step 11, posted by the Manager from the Builder's report as given (BACKLOG #3339, #3282, head I ran the Applied: Left open: the seven items listed under "Shipped open" in the PR body. |
|
Manager triage of the red
|
|
Lander: enqueued at b7b1d84, pinned.
|
|
Lander: re-enqueued at b7b1d84, the same pinned head. The eviction at 22:23:24Z (merge-group run 39332349173) was test_ui_dr_outlive::test_a_console_release_cut_off_by_the_deadline_still_completes on web console windows-2022, 1 failed / 1096 passed. That is the deadline race filed as vault #3871, its third hit today across three PRs (2387 ubuntu, 2436 windows-2025, this one windows-2022). This PR touches no DR code. |
|
CI failed in Its own head can still be green: the queue revalidates the merge, and the path gates that skip on a pull request run there. Read the run before retrying. https://github.com/MEFORORG/MessageFoundry/actions/runs/39332349173 |
|
Manager triage of the merge-queue ejection, run 39332349173 (
No code change pushed. The DR-outlive test has now failed twice in one evening and needs its own ledger row, for the Lander to file. |
|
CI failed in Its own head can still be green: the queue revalidates the merge, and the path gates that skip on a pull request run there. Read the run before retrying. https://github.com/MEFORORG/MessageFoundry/actions/runs/39335750057 |
|
Lander: re-enqueued at b7b1d84, the same pinned head. This eviction (23:05:30Z, merge-group run 39335750057) was a third, unrelated flake: tests/test_stage_dispatcher.py::test_adr0070_8_correlated_outage_single_reload_rearms_all[sqlserver] on sql server (store + connector) 2025. This PR touches no dispatcher or store code. Each of its three evictions was a different test, and none is in its diff. |
|
Manager triage of the third merge-queue ejection, run 39335750057 (
|
|
Security failed in Its own head can still be green: the queue revalidates the merge, and the path gates that skip on a pull request run there. Read the run before retrying. https://github.com/MEFORORG/MessageFoundry/actions/runs/39340479880 |
|
Manager triage of the fourth merge-queue ejection, Security run 39340479880 (
|
|
Lander: re-enqueued at b7b1d84, the same pinned head. Fourth eviction (23:18:41Z, Security merge-group run 39340479880): dependency-and-secret-scan failed closed because it could not reach PyPI ("The handshake operation timed out"). That is a transient network failure, and the gate refusing while blind is correct. This PR changes none of pyproject.toml, uv.lock or requirements.lock. Each of its four evictions had a different cause, none in its diff. |
Batch 294 (auth), items #3339 and #3282. This PR gets its own because #3339 changes a security control: what the
auth.logoutaudit row records, through a now-requiredclientkeyword onAuthService.logout. #3282 rides along because its commits are interleaved with #3339's on the Builder's branch, and splitting them out would mean rewriting the Builder's history. It is a WARNING rewording in the same file, with no control change.Merge danger -- #3339
Reversible: yes -- a revert on
mainundoes all of it.Blast radius:
AuthService.logoutinmessagefoundry/auth/service.py(new requiredclientkeyword);POST /auth/logoutinmessagefoundry/api/auth_routes.pyand/ui/logoutinmessagefoundry_webconsole/routes/core.py(both passclient_ip(request)); the web console seam digest moves5d9c162790077dfc->1f2d208818510f18(messagefoundry/api/_ui_seam.py,messagefoundry_webconsole/__init__.py,tests/golden/webconsole_seam.snapshot), so any other seam-moving branch clashes on that value by design (BACKLOG #1220). Routes answer the same as before.Evidence -- #3339
main6d6986fdd,AuthService.logouthas no client parameter and neither route passes one, so everyauth.logoutrow has a NULL client.auth.logoutrow back and asserts actor, client and outcome, with sign-in and sign-out from different pinned addresses. The/ui/logoutcontrol signs out with a cookie naming no session and expects(None, <address>, nothing_to_revoke). The JSON route's control is the existing rotation-race test, which now also checks actor and client. A service-level test checksclientreaches the row on both outcomes.Merge danger -- #3282
Reversible: yes.
Blast radius: the text of one start WARNING (
AuthService.report_administrators_needing_an_outside_service).logging_setup.pyandsecretscrub.pyare untouched.Evidence -- #3282
tests/_phi_log_capture.filtered_sink, the_install_phi_filterschain) losesdir-a(the control).main's wording swapped back in, the test fails.Source branch
b294-3339-3282, headb7b1d8417fbb0ad6c178cbd79359a827dcc391a8, onmain6d6986fdd.80b836029build,69d2c6088review round 1,8662c5573round 2 (reverts round 1's owner pre-read),3411694c0branch-review follow-ups6d3f81646build,b7b1d8417changelog limitsgit merge-treeagainst PR 2387's head and against batch 294's other branch (b294-3350) both exit 0.Builder report (summarised by the Manager; the full text is in the commit messages)
#3339 -- BUILT, one part still open.
AuthService.logouttakes a REQUIREDclientkeyword (asrevoke_own_sessiondoes) and writes it on theauth.logoutrow. Five existing test call sites passclient=None.detail.outcomenothing_to_revokealready marks a sign-out that ended nothing. Code review argued the row asks for "its own event", not a detail field on the same action. The Lander or the owner decides whether step 2 is met.get_sessionreader, whichtests/test_session_seal.pyforbids. The pre-read was reverted, and the docstring and changelog say why.CHANGELOG.mdentry added (changelog.d/README.mdrequires one for a console change). Fragmentchangelog.d/3339.security.md.#3282 -- BUILT. Fragment
changelog.d/3282.fixed.md, which notes that a username shaped like a credential label or a date can still be rewritten by the filters, and that the audit row holds the full list. Claim released.Checks, on the final tree unless noted:
Shipped open (code review, for rows)
auth.logoutraises after the revoke,/ui/logoutreturns a 500 and never clears the cookie or sends Clear-Site-Data.ldap.py:2308("...SPNEGO token: %s"),uploads.py:2148and:2165("...next pass: %s"). The review suggests one test that checks every log format string against the filter chain.revoke_other_sessionsandrevoke_sessions_for_user(auth.session_revoked).docs/PHI.mdsection 6 still saysaudit_log.actoris "always populated", which PR 2384's NULL-actor rows contradict.auth.logoutcorrectly.auth.logoutrow readers in tests (#3749 item 9).Proposed vault banners (the Lander's to flip)