freerdp2-x11 assumed the FreeRDP 2.x package/binary naming, but newer
Debian/Ubuntu releases have moved to a 3.x package where the binary
may be xfreerdp3 instead of xfreerdp. Try both, and use whichever
binary actually ends up available.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
xfreerdp gives far more specific error output than GNOME Connections'
generic "Authentication failed: connection failed" message. Run on
the travel laptop, writes output to rdp-test-output.txt in this same
repo so it can just be committed/pushed back rather than pasted.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Renames bootstrap.sh to setup-local.sh to match its actual scope (the
travel laptop only) and adds setup-remote.sh for the machine you
Remote-SSH/RDP into, since that's a different machine's one-time setup
and was already living outside setup-local.sh's reach (same reasoning
as the existing Tailscale-SSH prerequisite).
setup-remote.sh configures GNOME's system-level RDP (works from a cold
GDM login screen, not just an existing session) restricted to the
tailscale interface via a ufw rule, a self-signed TLS cert, and RDP
credentials that are deliberately separate from the account password
and never cached - only prompted if unset. Shares step-tracking helpers
with setup-local.sh via a new lib.sh rather than duplicating them.
Tested the branching logic (credentials-already-set, RDP-already-
enabled, ufw-already-active-with-rule, ufw-inactive-confirm/decline)
against realistic stubbed command output. Caught and fixed a real bug
in the process: the inactive/active ufw check used a bare `grep -qi
active`, which also matches the substring inside "inactive" - it was
silently skipping the enable-confirmation gate and going straight to
adding a firewall rule on a firewall that was never turned on. Fixed
by anchoring the match.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Compacts the design discussion into a reference: the workflow model
(pure Remote-SSH by default, opportunistic local clones for
self-contained python+uv projects only), how to run the script, the
home-machine prerequisite (Tailscale SSH), and the gotchas hit while
building it (PATH issues after su, stale sudo group membership, the
token-paste-into-shell bug, the spurious-space host alias bug, and
the tailnet-wide MagicDNS requirement) so they don't need re-debugging.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Tailscale's raw HostName field is whatever the OS reports (e.g.
"Pixel 9" with a literal space for an Android device), which breaks
when written unquoted into an SSH config Host line - ssh_config treats
space-separated words as multiple patterns, not one literal name.
DNSName is already sanitized (hyphens, no spaces) for exactly this
purpose, so derive the alias from its first label instead.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The summary just said "all OK" and left you to figure out what to do.
Now it lists the tailnet hosts this run actually found and spells out
the exact VS Code Remote-SSH steps to reach one, instead of assuming
you remember from the design conversation.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
readline's bracketed-paste handling didn't reliably prevent the
paste-leaking-into-shell issue in practice (likely tmux/terminal
paste passthrough not cooperating). Reading raw stdin until EOF
(Ctrl-D) sidesteps the problem entirely - it doesn't depend on any
terminal capability, it just keeps consuming bytes including embedded
newlines until you explicitly signal you're done. Token is visible
while pasting now (no -s); acceptable since this only matters on a
personal machine where terminal history exposure isn't a concern.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Plain `read -rsp` has no paste awareness: a token with a trailing
newline (common from some "copy token" UI buttons) terminates the
read early, and whatever came after in the paste is left in the
terminal's input buffer - which the shell then executes as a command
once the script exits. `read -e` uses GNU readline, which honors
bracketed paste and inserts a multi-line paste as literal text
instead of treating embedded newlines as Enter.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Print length + first/last 4 chars of the captured token instead of
the full secret, and strip stray whitespace (a trailing newline in a
copied token can silently truncate what read captures mid-paste).
Helps distinguish a truncated paste from an actually-wrong token
without exposing the credential in scrollback.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Persist the last-entered values to ~/.config/travel-bootstrap/config
and offer them as the prompt default, so a re-run only needs Enter
instead of retyping the same values every time.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
curl -f collapsed auth failures, wrong paths, and real network errors
into the same vague "could not reach" message. Now reports the actual
HTTP status and response body, and prompts print exactly where to
generate a Forgejo access token before asking for it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Idempotent setup for a disposable Debian travel laptop: base packages
(vim, tmux, mosh, tailscale, uv, VS Code + Remote-SSH, firefox-esr),
tailscale join, SSH config regenerated from live tailnet peers (wildcard
+ per-peer entries), fresh SSH key registered to Forgejo via API, and
Firefox hardened to forced-incognito with no history and forced uBlock
Origin. No repos cloned by default - workflow starts as pure Remote-SSH
to the home machine, local clones added opportunistically per project.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>