Move SSD source key guards to typed Kotlin

ober

cd734ac92b175d7b1fc37dba26231d81fb32a1d0

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index d4f688b..fff8431 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -5930,7 +5930,8 @@
         (export safePathComponent safePathComponentInvalid
                 safeLeaf safeLeafInvalid
                 safeZipEntryName zipEntryNameUnsafe validSourceKey
-                validatedSourceKey treeFileMime
+                validatedSourceKey validatedSourceKeyPresent validatedSourceKeyOrEmpty
+                treeFileMime
                 safeTreePathParts treePathLeaf treePathDirectoryParts
                 safeImportLeafEntryName zipEntryRootName zipEntryLeafName
                 zipEntryRootKind
@@ -6027,7 +6028,11 @@
           (let ((key (string-trim raw)))
             (if (validSourceKey key)
               (nullable-some key)
-              (nullable-none String))))))
+              (nullable-none String))))
+        (def (validatedSourceKeyPresent (key : (Nullable String))) : Bool
+          (not (nullable-null? key)))
+        (def (validatedSourceKeyOrEmpty (key : (Nullable String))) : String
+          (if (nullable-null? key) "" (nullable-get key)))))
 
     (typed-kotlin-file "com/sfb/ssdreview/NetworkSafety.kt"
       (kotlin-imports (java io InputStream)
@@ -8575,8 +8580,9 @@
        "    }"
        ""
        "    fun truthPath(sourceKey: String): File {"
-       "        val key = validatedSourceKey(sourceKey)"
-       "            ?: throw IllegalArgumentException(\"Invalid source key\")"
+       "        val validated = validatedSourceKey(sourceKey)"
+       "        if (!validatedSourceKeyPresent(validated)) throw IllegalArgumentException(\"Invalid source key\")"
+       "        val key = validatedSourceKeyOrEmpty(validated)"
        "        return containedLeaf(groundTruthDir, truthFileName(sha256Hex(key.toByteArray())))"
        "    }"
        ""
@@ -8629,8 +8635,9 @@
        ""
        "    @Synchronized"
        "    fun saveTruthSnapshot(truth: JSONObject): File {"
-       "        val sourceKey = validatedSourceKey(truthSourceKey(truth))"
-       "            ?: throw IllegalArgumentException(\"Invalid source key\")"
+       "        val validatedSource = validatedSourceKey(truthSourceKey(truth))"
+       "        if (!validatedSourceKeyPresent(validatedSource)) throw IllegalArgumentException(\"Invalid source key\")"
+       "        val sourceKey = validatedSourceKeyOrEmpty(validatedSource)"
        "        val truthFile = truthPath(sourceKey)"
        "        atomicWriteText(truthFile, truth.toString(2))"
        "        invalidateTruthIndex()"
@@ -8950,7 +8957,9 @@
        "        modified: Long,"
        "        replaceIfMoreComplete: Boolean = false"
        "    ): Boolean {"
-       "        val key = validatedSourceKey(truthSourceKey(truth)) ?: return false"
+       "        val validated = validatedSourceKey(truthSourceKey(truth))"
+       "        if (!validatedSourceKeyPresent(validated)) return false"
+       "        val key = validatedSourceKeyOrEmpty(validated)"
        "        val dest = truthPath(key)"
        "        val text = truth.toString(2)"
        "        val compareMoreComplete = shouldCompareMoreCompleteTruth(replaceIfMoreComplete, dest)"