From 44e1eb563be48b37a5fbfe1d423f224bb9bfcfeb Mon Sep 17 00:00:00 2001
From: Vasilii Iakliushin <viakliushin@gitlab.com>
Date: Thu, 15 Feb 2024 10:37:18 +0100
Subject: [PATCH] Extend ref extraction logic to support SHA256 commits

Contributes to https://gitlab.com/gitlab-org/gitlab/-/issues/419905

**Problem**

The regular expression used for commit hash detection supports only SHA1
format.

**Solution**

Adjust the regular expression to capture SHA256 commits too.
---
 .../gitlab_com_derisk/ref_extract_sha256.yml  |  9 +++++
 lib/extracts_ref.rb                           |  9 ++++-
 .../path_extraction_shared_examples.rb        | 40 ++++++++++++++++++-
 3 files changed, 55 insertions(+), 3 deletions(-)
 create mode 100644 config/feature_flags/gitlab_com_derisk/ref_extract_sha256.yml

diff --git a/config/feature_flags/gitlab_com_derisk/ref_extract_sha256.yml b/config/feature_flags/gitlab_com_derisk/ref_extract_sha256.yml
new file mode 100644
index 000000000000..84370a6c36c5
--- /dev/null
+++ b/config/feature_flags/gitlab_com_derisk/ref_extract_sha256.yml
@@ -0,0 +1,9 @@
+---
+name: ref_extract_sha256
+feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/419905
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/144853
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/442021
+milestone: '16.10'
+group: group::source code
+type: gitlab_com_derisk
+default_enabled: false
diff --git a/lib/extracts_ref.rb b/lib/extracts_ref.rb
index af3f841ea6ed..90414d3f98b4 100644
--- a/lib/extracts_ref.rb
+++ b/lib/extracts_ref.rb
@@ -109,8 +109,15 @@ def ref_type
   def extract_raw_ref(id)
     return ['', ''] unless repository_container
 
+    sha_regex =
+      if Feature.enabled?(:ref_extract_sha256, Feature.current_request)
+        /^(\h{40}\h{24}?)(.*)/
+      else
+        /^(\h{40})(.+)/
+      end
+
     # If the ref appears to be a SHA, we're done, just split the string
-    return $~.captures if id =~ /^(\h{40})(.+)/
+    return $~.captures if id =~ sha_regex
 
     # No slash means we must have a ref and no path
     return [id, ''] unless id.include?('/')
diff --git a/spec/support/shared_examples/path_extraction_shared_examples.rb b/spec/support/shared_examples/path_extraction_shared_examples.rb
index 5ceaf182d03d..6bc6a84e8b4c 100644
--- a/spec/support/shared_examples/path_extraction_shared_examples.rb
+++ b/spec/support/shared_examples/path_extraction_shared_examples.rb
@@ -79,12 +79,30 @@
         expect(extract_ref('v2.0.0')).to eq(['v2.0.0', ''])
       end
 
-      it 'extracts a valid commit ref without a path' do
+      it 'extracts a valid commit SHA1 ref without a path' do
         expect(extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062')).to eq(
           ['f4b14494ef6abf3d144c28e4af0c20143383e062', '']
         )
       end
 
+      it 'extracts a valid commit SHA256 ref without a path' do
+        expect(extract_ref('34627760127d5ff2a644771225af09bbd79f28a54a0a4c03c1881bf2c26dc13c')).to eq(
+          ['34627760127d5ff2a644771225af09bbd79f28a54a0a4c03c1881bf2c26dc13c', '']
+        )
+      end
+
+      context 'when feature flag "ref_extract_sha256" is disabled' do
+        before do
+          stub_feature_flags(ref_extract_sha256: false)
+        end
+
+        it 'cannot extract a valid commit SHA256 ref' do
+          expect(extract_ref('34627760127d5ff2a644771225af09bbd79f28a54a0a4c03c1881bf2c26dc13c')).to eq(
+            %w[34627760127d5ff2a644771225af09bbd79f28a5 4a0a4c03c1881bf2c26dc13c]
+          )
+        end
+      end
+
       it 'falls back to a primitive split for an invalid ref' do
         expect(extract_ref('stable')).to eq(['stable', ''])
       end
@@ -112,12 +130,30 @@
         expect(extract_ref('v2.0.0/CHANGELOG')).to eq(['v2.0.0', 'CHANGELOG'])
       end
 
-      it 'extracts a valid commit SHA' do
+      it 'extracts a valid commit SHA1' do
         expect(extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG')).to eq(
           %w[f4b14494ef6abf3d144c28e4af0c20143383e062 CHANGELOG]
         )
       end
 
+      it 'extracts a valid commit SHA256' do
+        expect(extract_ref('34627760127d5ff2a644771225af09bbd79f28a54a0a4c03c1881bf2c26dc13c/CHANGELOG')).to eq(
+          %w[34627760127d5ff2a644771225af09bbd79f28a54a0a4c03c1881bf2c26dc13c CHANGELOG]
+        )
+      end
+
+      context 'when feature flag "ref_extract_sha256" is disabled' do
+        before do
+          stub_feature_flags(ref_extract_sha256: false)
+        end
+
+        it 'cannot extract a valid commit SHA256 ref' do
+          expect(extract_ref('34627760127d5ff2a644771225af09bbd79f28a54a0a4c03c1881bf2c26dc13c/CHANGELOG')).to eq(
+            ['34627760127d5ff2a644771225af09bbd79f28a5', '4a0a4c03c1881bf2c26dc13c/CHANGELOG']
+          )
+        end
+      end
+
       it 'falls back to a primitive split for an invalid ref' do
         expect(extract_ref('stable/CHANGELOG')).to eq(%w[stable CHANGELOG])
       end
-- 
GitLab