be5cbe094825357e026912debc79944cc15bacde hiram Sun Sep 27 12:58:52 2026 -0700 claude review fixing bugs better safety on database assembly mash sketch archive refs #34360 diff --git src/hg/utils/automation/AssemblyDivergence.pm src/hg/utils/automation/AssemblyDivergence.pm index 07ca47bb6f1..0ec5164f10c 100644 --- src/hg/utils/automation/AssemblyDivergence.pm +++ src/hg/utils/automation/AssemblyDivergence.pm @@ -91,32 +91,42 @@ my $base = basename($path); $base =~ s/\.(2bit|fa|fasta)(\.gz)?$//; return $base; } # sketch($seq, $workDir, $tag, $regenerate) -> path to a .msh file for $seq. # $seq can be an existing sequence file path, a bare GenArk accession # (e.g. GCA_939628115.1), or a bare UCSC database name (e.g. hg38). # # The persistent mashSketch/ cache -- and everything needed to find # it -- lives entirely under $HgAutomate::clusterData # (/hive/data/genomes/), which is reachable from every cluster node. # This deliberately never touches /gbdb/ or hgcentraltest: cluster # jobs can't reach hgwdev (where hgcentraltest lives) and shouldn't # try, and /gbdb isn't mounted on cluster nodes at all. So: +# - a GenArk accession only qualifies for the persistent cache when +# mashSketchDir() finds a real on-disk <asmId>_* build directory; +# a UCSC db name only qualifies when $HgAutomate::clusterData/$db +# is a real directory. Both are pure filesystem checks (no ssh), +# and both exist so an arbitrary local file that merely happens to +# share a real assembly's basename (e.g. a stray /tmp/hg38.2bit) +# can't get cached into -- and silently corrupt -- that assembly's +# real, shared cache. Anything not backed by a real build/db +# directory falls through to the -workDir one-off sketch instead. # - a GenArk accession or UCSC db name with an already-cached .msh -# is a pure clusterData filesystem check -- always works, anywhere. +# is then just a pure clusterData filesystem check -- always +# works, anywhere. # - on a cache MISS, this only proceeds if $seq already IS a real, # existing sequence file (i.e. the caller resolved it themselves, # e.g. to a GenArk build-tree .2bit under clusterData, or handed a # literal /gbdb/... path from somewhere that does have it mounted) # -- a bare name with no cache and no real file in hand just fails # (see the final croak below), it never goes looking for one. # # Cached sketches accumulate once per assembly and are shared by # every future comparison involving it, cluster run or standalone # mashDistance.pl check alike. Anything that isn't a GenArk accession # or a recognized UCSC db falls back to a one-off sketch named # mashSketch.$tag.msh under $workDir, as before. sub sketch { my ($seq, $workDir, $tag, $regenerate) = @_; my $prefix; @@ -143,31 +153,38 @@ my $buildDir = $cacheDir; $buildDir =~ s#/mashSketch$##; my $builtSeq = "$buildDir/" . basename($buildDir) . ".2bit"; if (-e $builtSeq) { make_path($cacheDir) if (! -d $cacheDir); $prefix = "$cacheDir/$accession"; $id = $accession; $srcSeq = $builtSeq; } } } } if (! $prefix) { my $db = &seqBaseName($seq); - if ($db ne '') { + # Require a real /hive/data/genomes/$db directory before trusting + # $db as an actual UCSC assembly -- pure filesystem check, mirroring + # mashSketchDir()'s build-directory requirement for GenArk above. + # Without this, any existing sequence file whose basename happens to + # match a real db name (e.g. a stray local /tmp/hg38.2bit passed via + # -target2Bit) would get cached straight into -- and silently + # corrupt -- that db's real, shared production cache. + if ($db ne '' && -d "$HgAutomate::clusterData/$db") { my $cacheDir = "$HgAutomate::clusterData/$db/mashSketch"; if (! $regenerate && -e "$cacheDir/$db.msh") { return "$cacheDir/$db.msh"; # cache hit -- pure filesystem, done } # Not cached yet -- only proceed with a source we already have in # hand (see the sub's header comment above); never search for one. if (-e $srcSeq) { make_path($cacheDir) if (! -d $cacheDir); $prefix = "$cacheDir/$db"; $id = $db; } } } if (! $prefix) {