feat(screen): share the container's screen in a browser, driving nothing - #7
Merged
magicabdel merged 5 commits intoAug 23, 2026
Merged
Conversation
`--web` mints a token for every session and puts it in the link, so the browser keeps the old link in its history and offers it back in the address bar. The next session refuses it with `wrong token`, two words in plain text: true, and no help at all. The reader cannot tell it from a broken viewer, and the one thing they have to do — take the link this run printed — is not in it. A refused page load now answers with a page that says the link belongs to an older session, that the terminal printed the current one, and that the address bar completes the stale one. The paths the script calls keep the plain body, because it reads the status and never the text. The printed instructions say the same thing, at the point where the reader is about to copy the link.
`portal_stop` sent TERM and returned. Two things then happened on a timing that nobody controls. The teardown that follows it asks `auto_detach_after_gui` to return the container to headless, and that skips while a GUI app is running — so a detach that raced the exit left the container forwarding a display with nothing on it. `status` then reports "Display fwd: on (GUI session active)" for a session that ended minutes ago, and neither the reader nor the next run can tell that from a sign-in in progress. That is the state a machine was found in after a `--web` session that had already finished. The second is worse and is coming: `intune-portal` is a single instance, so a command that closes one and starts another hands its request to the process on the way out, and the display it just made stays empty. So the close waits for the exit, bounded at ten seconds and with a warning when the portal outlasts it. TERM is still what it sends: the portal writes the broker's account state on the way out, and waiting is what lets it finish.
… race Finding a free number and starting a server on it are two steps, and another process can take the number in between. The loser reported "Xvfb exited immediately" and the command failed, although twenty-one other numbers were free. It was reachable only from the test suite until now — two X11 tests each take the first free display, so running them together failed about half the time — but a screen share makes it a user's problem: two of them started in the same second race exactly like that. A failure whose number is taken NOW, having been free a moment ago, was taken by somebody else, so the search moves on. A failure that leaves the number free — Xvfb missing, a geometry it refuses — is reported as it is rather than tried twenty-one more times. Nothing is matched against Xvfb's text, so nothing depends on how it words itself. The message it does print is worth having: Xvfb opens with pages of xkbcomp keysym warnings, so the first line said "The XKEYBOARD keymap compiler (xkbcomp) reports:" and sent the reader after a keyboard problem they did not have. The reason is on the error line after them, and that is what the message now carries. The search also stops at :98 rather than :99, which is the container's own compliance agent display: it was excluded in practice, because its socket is in the bound-in /tmp/.X11-unix, and it is excluded on purpose now.
Two ways the browser viewer showed a reader black pixels and left them to guess. A portal window is 478×628 on the 1280×800 display it is given, and the viewer sent the display. Two thirds of the page was therefore desktop that nobody had drawn on, with the window in a corner — and a reader who opens that reasonably concludes the viewer is broken. It now sends the box around the windows: the union of every mapped window big enough to be real, read from the X geometry rather than from the pixels (the terminal viewer's brightness scan would crop a dark-themed window to the light part of it). The union, not the topmost window, because the identity broker opens its Authentication dialog beside the portal rather than over it. The picture therefore changes size while the session runs, so the page takes the canvas size from each answer instead of from the page load, and a click is put back on the display by the box's origin before XTEST sees it. The whole-frame repaint that a size change needs was already there: a diff is only taken against a frame of the same size. The other way is the display that genuinely has nothing on it, for the half minute the portal takes to draw. The status line said "waiting for the sign-in window", but it is one line under a large black rectangle, and the rectangle is what the reader is looking at. The reason is now on the picture, and it goes when a window arrives. Placing and focusing a window no longer refuses a keystroke when it fails. There is no window manager on this display, so the call races the window it names: a dialog that closes between the capture and the keystroke makes the request name a window the server has forgotten. Dropping the keystroke for that is the wrong trade, since XTEST sends it to whatever holds the focus. The end-to-end test types its line more than once if it has to. The window being up is what it can see; a shell inside it being ready to read is not, and on a loaded machine the first line can arrive before the prompt.
`login` signs in for you: it presses Sign in, types the address and the password, and closes what it opened. A reader who wants to do the steps themselves — read what Intune says, answer a prompt it did not expect, follow a conditional-access page — has no command for that. Using `login --web` for it means an automation is pressing buttons under them. `screen` streams instead. It starts the Intune portal, so the first screen is there without a second command, and from that point it touches nothing: the portal, the identity broker's Authentication dialog and an Edge window all appear as they are, and the reader's own keyboard and mouse go to them. It looks for a display before it makes one, which is the difference between working and a black page. `intune-portal` is a single instance: a second launch hands its request to the running one and exits, so a command that insists on its own display gets a display with nothing on it while the portal draws on the one some earlier session made. That is exactly how a reader ends up watching black pixels with everything apparently running. So a display in this tool's range that already has a window on it is the one shared, and a share that finds a display leaves it alone when it closes — only a share that opened one closes it. A portal running with no display at all is the third case, and it is unreachable rather than merely invisible: its display went with the session that made it. That one is closed before a new one starts, because the launch would otherwise reach the single instance on the way out.
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.
Stacked on #6 — its commit is the first of the five here and disappears from this
diff when #6 merges.
The report
login --webshowed a black page with everything apparently running.Why it was black
loginsession from an earlier hour was still alive and ownedintune-portalon its own display,
:77.--webrun made:78and asked the container to start the portal.intune-portalis a single instance. The second launch handed its request tothe process on
:77and exited, so:78never had a window on it.portal_is_runninggreps the process name, so it found the old portal andreported the portal as up. Nothing in the page said otherwise.
What is here
screen, a new command. It streams; it does not sign in. It starts the portal sothe first Intune screen is there without a second command, and from that point it
touches nothing: the portal, the broker's Authentication dialog and an Edge window
all appear as they are, and the reader drives them.
loginis unchanged.It looks for a display before it makes one — a display in this tool's range that
already has a window is the one it shares — so case 3 above streams the portal that
exists instead of an empty screen. A share that finds a display leaves it running;
only a share that opened one closes it. A portal running with no display is
closed first, because it is unreachable and would otherwise absorb the next launch.
The viewer sends the windows, not the display. A 478×628 portal on a 1280×800
screen meant two thirds of the page was undrawn desktop. It now sends the union of
the mapped windows, read from the X geometry rather than from a brightness scan, so a
dark-themed window is not cropped to its light part. The picture therefore changes
size mid-session: the canvas takes its size from each answer, and a click is put back
on the display by the box's origin before XTEST sees it.
A screen with nothing on it says so on the picture. The status line already said
it, but it is one line under a large black rectangle.
Two fixes underneath.
portal_stopnow waits for the exit. It sent TERM and returned, so the detach thatfollows saw a GUI app running and skipped — which is why a machine was found
reporting
Display fwd: on (GUI session active)for a session that had ended. Itis also what makes the close-then-start above reach a container with no instance.
Xvfb::starttakes the next display number when another process wins the racebetween finding a free one and starting a server on it. Two screen shares started in
the same second race exactly like that; two X11 tests run together already did, and
failed about half the time. Nothing is matched against Xvfb's text — the number
being taken now, having been free a moment ago, is the signal. The failure message
also stopped quoting the xkbcomp keysym warnings Xvfb opens with and now carries the
error line.
no window manager, so the call races the window it names.
Tested
cargo test --lib: 89 passed.cargo fmt --checkandcargo clippy --all-targets -- -W clippy::all: clean.run together at all before the Xvfb fix.
screenstreams the Intune Agentfirst screen at 478×628; a click on Sign in sent from the browser reaches the
portal and starts the identity broker; a second
screenshares the first one'sdisplay instead of showing black, and leaves it running when it closes; a stale
portal with a dead display is recovered; Finish closes the portal, drops the
display and returns the container to headless.