updates

ober

6b2d9dd6893775ab9c1f409353c10e6503f06dd8

diff --git a/gitsafe/scanner.ss b/gitsafe/scanner.ss
index 9cfa7c7..02a4b85 100644
--- a/gitsafe/scanner.ss
+++ b/gitsafe/scanner.ss
@@ -257,6 +257,45 @@
            #t]
           [else (loop (+ i 1))]))))
 
+  ;; Absolute filesystem paths often contain long alphanumeric directory
+  ;; components that fit the permissive base64 regex. They name locations,
+  ;; not credentials; precise credential patterns still run on these lines.
+  (def (in-absolute-path-context? line match-start)
+    (or (and (< match-start (string-length line))
+             (char=? (string-ref line match-start) #\/))
+        (let loop ([i (- match-start 1)])
+          (cond
+            [(< i 0) #f]
+            [(char=? (string-ref line i) #\/) #t]
+            [(or (char=? (string-ref line i) #\space)
+                 (char=? (string-ref line i) #\tab)
+                 (char=? (string-ref line i) #\"))
+             #f]
+            [else (loop (- i 1))]))))
+
+  ;; Documentation often lists identifiers as `a/b/c/.../`. A long list can
+  ;; resemble base64 only because the base64 alphabet admits slash; its
+  ;; repeated separators and trailing slash distinguish it from a token.
+  (def (slash-delimited-identifier-list? matched)
+    (and (string-suffix? "/" matched)
+         (not (string-contains matched "+"))
+         (not (string-contains matched "="))
+         (>= (length (string-split matched #\/)) 5)))
+
+  ;; Published digest test vectors are deterministic examples, not secrets.
+  ;; Keep this intentionally small: arbitrary hashes still receive entropy
+  ;; scanning unless another contextual suppression applies.
+  (def *well-known-hash-test-vectors*
+    '("d41d8cd98f00b204e9800998ecf8427e"
+      "900150983cd24fb0d6963f7d28e17f72"
+      "da39a3ee5e6b4b0d3255bfef95601890afd80709"
+      "a9993e364706816aba3e25717850c26c9cd0d89d"
+      "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+      "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"))
+
+  (def (well-known-hash-test-vector? matched)
+    (member matched *well-known-hash-test-vectors*))
+
   (def *git-sha-prefix-re*
     (re "(?i:(^|[^A-Za-z0-9_])(?:old\\s+head|new\\s+head|old|new|head|commit|revision|rev|object|tree|parent|merge|merged|checkout|reset|rebase|tag)[^A-Za-z0-9_]{0,24}$)"))
 
@@ -615,6 +654,9 @@
                                         file line (re-match-start m))))
                             (and (member pid *url-sensitive-patterns*)
                                  (or (in-url-context? line (re-match-start m))
+                                     (in-absolute-path-context? line (re-match-start m))
+                                     (slash-delimited-identifier-list? matched)
+                                     (well-known-hash-test-vector? matched)
                                      (in-digest-context? line (re-match-start m))
                                      (in-git-sha-context? line (re-match-start m) matched)
                                      (in-dockerfile-from? line))))
diff --git a/test/test-gitsafe.ss b/test/test-gitsafe.ss
index 590e1af..f0ddd3c 100644
--- a/test/test-gitsafe.ss
+++ b/test/test-gitsafe.ss
@@ -854,6 +854,38 @@
                                        findings)])
         (check-equal? '() entropy-findings)))
 
+    (test-case "scan-content: absolute filesystem paths are not entropy secrets"
+      (let* ([c (default-config)]
+             [findings (scan-content "handoff.md"
+                         "smoke script in /var/folders/01/7797pkc13nq0x1fl7wxp1s0c0000gn/T/opencode/\n"
+                         c)])
+        (check-equal? '() (filter (lambda (f)
+                                    (member (finding-pattern-id f)
+                                            '(high-entropy-base64 high-entropy-hex)))
+                                  findings))))
+
+    (test-case "scan-content: slash-delimited documentation lists are not entropy secrets"
+      (let* ([c (default-config)]
+             [findings (scan-content "Project.md"
+                         "extension/optimizer/memory/log/prepared/variable/secret/temp/cache/count/\n"
+                         c)])
+        (check-equal? '() (filter (lambda (f)
+                                    (member (finding-pattern-id f)
+                                            '(high-entropy-base64 high-entropy-hex)))
+                                  findings))))
+
+    (test-case "scan-content: standard digest test vectors are not entropy secrets"
+      (let* ([c (default-config)]
+             [findings (scan-content "digest-test.ss"
+                         (string-append
+                           "sha1 empty: da39a3ee5e6b4b0d3255bfef95601890afd80709\n"
+                           "sha256 abc: ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad\n")
+                         c)])
+        (check-equal? '() (filter (lambda (f)
+                                    (member (finding-pattern-id f)
+                                            '(high-entropy-base64 high-entropy-hex)))
+                                  findings))))
+
     (test-case ".gitsafeignore ** does not skip files (integration)"
       ;; A hostile in-repo .gitsafeignore containing "**" must not cause all
       ;; files to be skipped; the secret is still scanned and reported.