798c382a4e6e6f2e9ecaf6c47300f8cc2a6e0074
braney
  Mon Aug 24 08:54:58 2026 -0700
ts: add a conf subcommand to rewrite httpd.conf without re-freezing, refs #37867

The CORS scoping fix in 4d9755a1 changed the httpd.conf template, but a
parked instance keeps the conf it was created with.  All three parked
instances therefore still set Access-Control-Allow-Origin at server
scope, including on cgi-bin.  That is the hole 4d9755a1 closed in the
template only.

The one way to pick up a template change was "ts sync", and cmd_sync
calls freeze before writeConf.  For a park whose whole point is the
frozen code, re-freezing to the current live sandbox throws away the
thing being kept.  There was no way to update only the config.

"ts conf NNNNN" rewrites httpd.conf from the current template, leaves
the frozen cgi-bin and htdocs alone, and restarts the httpd if it was
running.  Ran it on all three parked instances: cgi-bin now sends no
Access-Control header, htdocs and trash send both.

diff --git src/utils/ts/README src/utils/ts/README
index 0bb10fc7f01..9a42a44631a 100644
--- src/utils/ts/README
+++ src/utils/ts/README
@@ -1,66 +1,67 @@
 ts - ticket sandboxes
 =====================
 
 ts parks a Redmine ticket as its own frozen browser instance on hgwdev.  You can
 leave the ticket, work on something else, and return to it later.  You can also
 give a reviewer a URL for it.  refs #37867
 
 Only the code is frozen.  Each parked instance holds a full copy of your live
 cgi-bin-$USER and htdocs-$USER, plus a rewritten hg.conf.  The MySQL databases,
 /gbdb, and the browser trash stay shared with the live CGIs.  A private httpd,
 running as you, serves the copy on a loopback high port.  It needs no root, no
 DNS, and no vhost.
 
 Two files:
 
   ts       the real tool.  Runs on hgwdev.
   ts.mac   a thin wrapper for your laptop.  It runs ts subcommands over ssh and
            opens the local ssh -L tunnel.  Install it as "ts" on the laptop.
 
 Setup on hgwdev.  A freeze uses a few gigabytes per ticket, so keep the parked
 instances on a large local pool instead of your home directory:
 
   mkdir -p /data/home/$USER/ticketSandboxes
   ln -s /data/home/$USER/ticketSandboxes ~/ticketSandboxes
 
 Set TS_ROOT if you want them somewhere else.  Run "ts" with no arguments for the
 subcommand list.
 
 Typical use:
 
   ts create 37867 "some note"     freeze the live sandbox and start the httpd
   ts sync 37867                   re-freeze after more work on the live sandbox
+  ts conf 37867                   rewrite httpd.conf only, keeping the freeze
   ts list                         show every parked ticket and its status
   ts tunnel 37867                 open the tunnel and print the browser URL
   ts remove 37867                 stop the httpd and delete the instance
 
 Any hgwdev account can reach a parked instance, because all hgwdev users share
 the machine's loopback:
 
   ssh -N -L PORT:localhost:PORT you@hgwdev.gi.ucsc.edu
   # then open http://localhost:PORT/cgi-bin/hgTracks
 
 There is no password on a parked instance.  It shows only what any hgwdev user
 can already build and query.
 
 Notes
 -----
 
 The freeze is a full copy, not hardlinks.  Hardlinks only freeze a file against
 replacement by rename, so an in-place edit of a live file would also change the
 parked copy.
 
 The CGIs read two htdocs directories.  The frozen htdocs-$USER is the
 DocumentRoot, and the code also reads a sibling ../htdocs for files such as the
 URW fonts.  Each parked instance keeps a symlink to the shared
 /usr/local/apache/htdocs for that reason.  Without it, rendering fails because
 it cannot find a font file.
 
 Each instance draws its ticket number faintly across the page background, so you
 always know which frozen browser you are viewing.  ts writes that stylesheet
 into the frozen htdocs and sets browser.style in the frozen hg.conf.
 
 ts does not replace the tip/beta/rel Docker instances.  Those reproduce an exact
 released environment, including the database.
 
 Write-up: https://hgwdev.gi.ucsc.edu/~braney/per-rm-sandboxes.html