diff --git a/.gitleaksignore b/.gitleaksignore index 09288cde3ef724bedfd79b592f1cf7a3b8954f7d..32906f05b2accca50df84493d1de114f10c5ebcc 100644 --- a/.gitleaksignore +++ b/.gitleaksignore @@ -1 +1,2 @@ afedb913baf4203aa688421873fdb9f94649578e:doc/api/users.md:generic-api-key:2201 +spec/frontend/lib/utils/secret_detection_spec.js:generic-api-key:34 diff --git a/app/assets/javascripts/lib/utils/secret_detection.js b/app/assets/javascripts/lib/utils/secret_detection.js index 49de7b3a081667137b66d4cb96a9d932acf200a0..4d8612aeeff0a77f68ddaa01e728e93136823b18 100644 --- a/app/assets/javascripts/lib/utils/secret_detection.js +++ b/app/assets/javascripts/lib/utils/secret_detection.js @@ -28,6 +28,10 @@ export const containsSensitiveToken = (message) => { name: 'GitLab OAuth Application Secret', regex: `gloas-[0-9a-zA-Z_-]{64}`, }, + { + name: 'GitLab Deploy Token', + regex: `gldt-[0-9a-zA-Z_-]{20}`, + }, ]; for (const rule of sensitiveDataPatterns) { diff --git a/app/models/deploy_token.rb b/app/models/deploy_token.rb index 920321a1699c4e728ec0bc048937ded5044df501..1ab603b5ddf904ee7dd9412d76ed35faa0f5956d 100644 --- a/app/models/deploy_token.rb +++ b/app/models/deploy_token.rb @@ -6,13 +6,14 @@ class DeployToken < ApplicationRecord include PolicyActor include Gitlab::Utils::StrongMemoize - add_authentication_token_field :token, encrypted: :required - AVAILABLE_SCOPES = %i[read_repository read_registry write_registry read_package_registry write_package_registry].freeze GITLAB_DEPLOY_TOKEN_NAME = 'gitlab-deploy-token' + DEPLOY_TOKEN_PREFIX = 'gldt-' REQUIRED_DEPENDENCY_PROXY_SCOPES = %i[read_registry write_registry].freeze + add_authentication_token_field :token, encrypted: :required, format_with_prefix: :prefix_for_deploy_token + attribute :expires_at, default: -> { Forever.date } # Do NOT use this `user` for the authentication/authorization of the deploy tokens. @@ -141,6 +142,10 @@ def expires_at=(value) write_attribute(:expires_at, value.presence || Forever.date) end + def prefix_for_deploy_token + DEPLOY_TOKEN_PREFIX + end + private def expired? diff --git a/config/gitleaks.toml b/config/gitleaks.toml index 24761dfd7832e589c5dbe1700c20e6c5b6b3fc52..a492b38fdf96541da486f1452d6f1bdaacbb06bb 100644 --- a/config/gitleaks.toml +++ b/config/gitleaks.toml @@ -12,6 +12,7 @@ path = "/gitleaks.toml" "glpat-1234567890abcdefghij", # spec/frontend/lib/utils/secret_detection_spec.js "glpat-cgyKc1k_AsnEpmP-5fRL", + "gldt-cgyKc1k_AsnEpmP-5fRL", # spec/frontend/lib/utils/secret_detection_spec.js "GlPat-abcdefghijklmnopqrstuvwxyz", # doc/development/sec/token_revocation_api.md diff --git a/doc/security/token_overview.md b/doc/security/token_overview.md index 25ecb7f76e232d9e4de6c4de2b410a39db2b1ab3..4555459e7c5ff28574c758223fd7b1832ed6fa41 100644 --- a/doc/security/token_overview.md +++ b/doc/security/token_overview.md @@ -234,7 +234,7 @@ The following tables show the prefixes for each type of token where applicable. | Impersonation token | Not applicable. | | Project access token | Not applicable. | | Group access token | Not applicable. | -| Deploy token | Not applicable. | +| Deploy token | `gldt-` ([Added in GitLab 16.7](https://gitlab.com/gitlab-org/gitlab/-/issues/376752)) | | Deploy key | Not applicable. | | Runner registration token | Not applicable. | | Runner authentication token | `glrt-` | diff --git a/spec/frontend/lib/utils/secret_detection_spec.js b/spec/frontend/lib/utils/secret_detection_spec.js index 761062f0340da1d35cf269e78b32e345ca043bf5..a8da6e8969fa986b1ec8029f240f0a65e8b2af5d 100644 --- a/spec/frontend/lib/utils/secret_detection_spec.js +++ b/spec/frontend/lib/utils/secret_detection_spec.js @@ -31,6 +31,7 @@ describe('containsSensitiveToken', () => { 'token: gloas-a8cc74ccb0de004d09a968705ba49099229b288b3de43f26c473a9d8d7fb7693', 'https://example.com/feed?feed_token=123456789_abcdefghij', 'glpat-1234567890 and feed_token=ABCDEFGHIJKLMNOPQRSTUVWXYZ', + 'token: gldt-cgyKc1k_AsnEpmP-5fRL', ]; it.each(sensitiveMessages)('returns true for message: %s', (message) => { diff --git a/spec/models/deploy_token_spec.rb b/spec/models/deploy_token_spec.rb index 1b8dd62455ed181548ce520b17ce82b947d50e5c..36479dffe214fcc2da690fc37e8f2c22b0950784 100644 --- a/spec/models/deploy_token_spec.rb +++ b/spec/models/deploy_token_spec.rb @@ -473,4 +473,12 @@ expect(subject.impersonated?).to be(false) end end + + describe '.token' do + # Specify a blank token_encrypted so that the model's method is used + # instead of the factory value + subject(:plaintext) { create(:deploy_token, token_encrypted: nil).token } + + it { is_expected.to match(/gldt-[A-Za-z0-9_-]{20}/) } + end end diff --git a/spec/requests/api/deploy_tokens_spec.rb b/spec/requests/api/deploy_tokens_spec.rb index c0e36bf03bf194555d33227393c6d46106b5c2e8..2f215cd5bd131fca372254d751a89311181bd34c 100644 --- a/spec/requests/api/deploy_tokens_spec.rb +++ b/spec/requests/api/deploy_tokens_spec.rb @@ -395,6 +395,7 @@ expect(json_response['scopes']).to eq(['read_repository']) expect(json_response['username']).to eq('Bar') expect(json_response['expires_at'].to_time.to_i).to eq(expires_time.to_i) + expect(json_response['token']).to match(/gldt-[A-Za-z0-9_-]{20}/) end context 'with no optional params given' do