After new gdk instance install, following "Simple installation" guide, and running any spec, like bin/rspec ee/spec/models/ee/group_spec.rb:965, I see the following issue:
~/gdk/gitlab$ bin/rspec ee/spec/models/ee/group_spec.rb:965
Creating a backup of secrets file /home/bogdanvlviv/gdk/gitlab/config/secrets.yml at /home/bogdanvlviv/gdk/gitlab/tmp/tests/backups/secrets.yml.orig.1749764350
An error occurred while loading ./ee/spec/models/ee/group_spec.rb.
Failure/Error: super(connection, underlying_table(connection, table_name))
ActiveRecord::StatementInvalid:
PG::UndefinedTable: ERROR: relation "application_settings" does not exist
LINE 10: WHERE a.attrelid = '"application_settings"'::regclass
^
# ./lib/gitlab/database/schema_cache_with_renamed_table.rb:25:in `columns'
# ./lib/gitlab/database/schema_cache_with_renamed_table.rb:29:in `columns_hash'
# ./app/models/concerns/cacheable_attributes.rb:31:in `build_from_defaults'
# ./lib/gitlab/application_setting_fetcher.rb:52:in `in_memory_application_settings'
# ./lib/gitlab/application_setting_fetcher.rb:25:in `cached_application_settings'
# ./lib/gitlab/application_setting_fetcher.rb:11:in `current_application_settings'
# ./lib/gitlab/current_settings.rb:15:in `block in current_application_settings'
# ./gems/gitlab-safe_request_store/lib/gitlab/safe_request_store/null_store.rb:37:in `fetch'
# ./lib/gitlab/current_settings.rb:15:in `current_application_settings'
# ./lib/banzai/filter/asset_proxy_filter.rb:67:in `initialize_settings'
# ./config/initializers/asset_proxy_settings.rb:7:in `block in <main>'
# ./config/initializers/asset_proxy_settings.rb:6:in `<main>'
# ./config/environment.rb:7:in `<top (required)>'
# ./spec/spec_helper.rb:27:in `require_relative'
# ./spec/spec_helper.rb:27:in `<top (required)>'
# ./ee/spec/models/ee/group_spec.rb:3:in `<top (required)>'
# ------------------
# --- Caused by: ---
# PG::UndefinedTable:
# ERROR: relation "application_settings" does not exist
# LINE 10: WHERE a.attrelid = '"application_settings"'::regclass
# ^
# ./lib/gitlab/database/schema_cache_with_renamed_table.rb:25:in `columns'
Run options: include {:locations=>{"./ee/spec/models/ee/group_spec.rb"=>[965]}}
All examples were filtered out
Finished in 0.00004 seconds (files took 5.09 seconds to load)
0 examples, 0 failures, 1 error occurred outside of examples
To resolve that issue I had to run RAILS_ENV=test bin/rails db:setup. I didn't need to do that manually in the past.
Linux 6.11.0-26-generic #26~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Apr 17 19:20:47 UTC 2 x86_64 x86_64 GNU/Linux
x86_64
ruby 3.3.8 (2025-04-09 revision b200bad6cd) [x86_64-linux]
aac934e0
mise-en-place 2025.6.1 linux-x64 (2025-06-09)
PATH=$HOME/.local/share/mise/installs/node/20.12.2/bin:$HOME/.local/share/mise/installs/yarn/1.22.19/bin:$HOME/.local/share/mise/installs/redis/7.0.14/bin:$HOME/.local/share/mise/installs/minio/2022-07-15T03-44-22Z/bin:$HOME/.local/share/mise/installs/postgres/16.8/bin:$HOME/.local/share/mise/installs/postgres/14.9/bin:$HOME/.cargo/bin:$HOME/.local/share/mise/installs/ruby/3.3.8/bin:$HOME/.local/share/mise/installs/ruby/3.2.4/bin:$HOME/.local/share/mise/installs/shellcheck/0.10.0:$HOME/.local/share/mise/installs/markdownlint-cli2/0.18.1/bin:$HOME/.local/share/mise/installs/vale/3.11.2:$HOME/.local/share/mise/installs/go/1.24.4/bin:$HOME/.local/share/mise/installs/python/3.13.3/bin:$HOME/.local/share/mise/installs/sqlite/3.49.2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin:$HOME/.fzf/bin
LANG=en_US.UTF-8
LANGUAGE=
LC_ALL=en_US.UTF-8
LDFLAGS=
CPPFLAGS=
PKG_CONFIG_PATH=
LIBPCREDIR=
RUBY_CONFIGURE_OPTS=
---
asdf:
opt_out: true
gdk:
protected_config_files:
- gitlab/config/gitlab.yml
gitlab:
rails:
puma:
threads_max: 1
threads_min: 0
workers: 1
hostname: gdk.test
https:
enabled: true
mise:
enabled: true
nginx:
enabled: true
ssl:
certificate: gdk.test.pem
key: gdk.test-key.pem
omniauth:
group_saml:
enabled: true
openldap:
enabled: true
port: 3443
[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[33mW[0m[32m.[0m[32m.[0m[32m.[0m[33mW[0m[33mW[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[33mW[0m[32m.[0m[32m.[0m
⚠️ [33mWARNING[0m: Your GDK may need attention.
GDK Configuration
================================================================================
Please review the following diff(s) and/or consider running `gdk reconfigure`:
gitlab/config/gitlab.yml
--------------------------------------------------------------------------------
[36m@@ -899,19 +899,6 @@[m [mdevelopment:[m
<<: *base[m
omniauth:[m
[31m- allow_single_sign_on: true[m
[31m- auto_link_saml_user: false[m
[31m- block_auto_created_users: false[m
providers:[m
- { name: 'group_saml' }[m
[31m- - { name: 'saml',[m
[31m- label: 'okta',[m
[31m- groups_attribute: 'groups',[m
[31m- args: {[m
[31m- assertion_consumer_service_url: 'https://gdk.test:3443/users/auth/saml/callback',[m
[31m- idp_cert_fingerprint: '47:AA:5B:E5:34:CA:64:10:1C:3B:BF:CF:A7:F1:9F:38:B8:A0:2F:3E:E4:01:1D:66:38:09:33:16:2E:38:56:B6',[m
[31m- idp_sso_target_url: 'https://trial-2663056.okta.com/app/trial-2663056_gdksamlsso_1/exks29bppguI4aztw697/sso/saml',[m
[31m- issuer: 'https://gdk.test:3443',[m
[31m- name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'[m
[31m- } }[m
[m
[m
[Correctable] Git Maintenance Recommendation
================================================================================
We recommend enabling git-maintenance to avoid slowdowns of local git operations like fetch, pull, and checkout.
To enable it, run `git maintenance start` in each repository:
git -C $HOME/gdk maintenance start
git -C $HOME/gdk/gitlab maintenance start
Stale Data
================================================================================
You might encounter a PG::CheckViolation error during database migrations, likely due to stale data in the ci database that belongs in the main database, or vice versa. To address this, you can run:
gdk truncate-legacy-tables
Telemetry
================================================================================
As GitLab team member, we kindly ask you to enable telemetry, which reports command durations and crashes back to the GDK maintainers, so we can improve GDK for all contributors.
To enable telemetry, run:
gdk telemetry
To opt out of this suggestion, run:
touch .cache/.no-telemetry-diagnostic
ℹ️ You may autocorrect 1 problem by running `gdk doctor --correct` or `gdk doctor -C`
RubyGems Environment:
- RUBYGEMS VERSION: 3.6.9
- RUBY VERSION: 3.3.8 (2025-04-09 patchlevel 144) [x86_64-linux]
- INSTALLATION DIRECTORY: $HOME/.local/share/mise/installs/ruby/3.3.8/lib/ruby/gems/3.3.0
- USER INSTALLATION DIRECTORY: $HOME/.local/share/gem/ruby/3.3.0
- CREDENTIALS FILE: $HOME/.local/share/gem/credentials
- RUBY EXECUTABLE: $HOME/.local/share/mise/installs/ruby/3.3.8/bin/ruby
- GIT EXECUTABLE: /usr/bin/git
- EXECUTABLE DIRECTORY: $HOME/.local/share/mise/installs/ruby/3.3.8/bin
- SPEC CACHE DIRECTORY: $HOME/.cache/gem/specs
- SYSTEM CONFIGURATION DIRECTORY: $HOME/.local/share/mise/installs/ruby/3.3.8/etc
- RUBYGEMS PLATFORMS:
- ruby
- x86_64-linux
- GEM PATHS:
- $HOME/.local/share/mise/installs/ruby/3.3.8/lib/ruby/gems/3.3.0
- $HOME/.local/share/gem/ruby/3.3.0
- GEM CONFIGURATION:
- :update_sources => true
- :verbose => true
- :backtrace => true
- :bulk_threshold => 1000
- REMOTE SOURCES:
- https://rubygems.org/
- SHELL PATH:
- $HOME/.local/share/mise/installs/node/20.12.2/bin
- $HOME/.local/share/mise/installs/yarn/1.22.19/bin
- $HOME/.local/share/mise/installs/redis/7.0.14/bin
- $HOME/.local/share/mise/installs/minio/2022-07-15T03-44-22Z/bin
- $HOME/.local/share/mise/installs/postgres/16.8/bin
- $HOME/.local/share/mise/installs/postgres/14.9/bin
- $HOME/.cargo/bin
- $HOME/.local/share/mise/installs/ruby/3.3.8/bin
- $HOME/.local/share/mise/installs/ruby/3.2.4/bin
- $HOME/.local/share/mise/installs/shellcheck/0.10.0
- $HOME/.local/share/mise/installs/markdownlint-cli2/0.18.1/bin
- $HOME/.local/share/mise/installs/vale/3.11.2
- $HOME/.local/share/mise/installs/go/1.24.4/bin
- $HOME/.local/share/mise/installs/python/3.13.3/bin
- $HOME/.local/share/mise/installs/sqlite/3.49.2/bin
- /usr/local/sbin
- /usr/local/bin
- /usr/sbin
- /usr/bin
- /sbin
- /bin
- /usr/games
- /usr/local/games
- /snap/bin
- /snap/bin
- $HOME/.fzf/bin
Bundler 2.6.5
Platforms ruby, x86_64-linux
Ruby 3.3.8p144 (2025-04-09 revision b200bad6cd40d08e9f33b93e1a85c270b337867c) [x86_64-linux]
Full Path $HOME/.local/share/mise/installs/ruby/3.3.8/bin/ruby
Config Dir $HOME/.local/share/mise/installs/ruby/3.3.8/etc
RubyGems 3.6.9
Gem Home $HOME/.local/share/mise/installs/ruby/3.3.8/lib/ruby/gems/3.3.0
Gem Path $HOME/.local/share/gem/ruby/3.3.0:$HOME/.local/share/mise/installs/ruby/3.3.8/lib/ruby/gems/3.3.0
User Home $HOME
User Path $HOME/.local/share/gem/ruby/3.3.0
Bin Dir $HOME/.local/share/mise/installs/ruby/3.3.8/bin
Tools
Git 2.49.0
RVM not installed
rbenv not installed
chruby not installed
Built At 2025-02-20
Git SHA cffd973142d
Released Version true
# frozen_string_literal: true
source 'https://rubygems.org'
gemspec path: 'gem/'
group :development do
gem 'lefthook', '~> 1.10.10', require: false
gem 'rubocop', require: false
gem "rubocop-rake", "~> 0.6.0", require: false
gem 'yard', '~> 0.9.37', require: false
gem 'pry-byebug' # See doc/howto/pry.md
end
group :test do
gem 'gitlab-styles', '~> 13.0.2', require: false
gem 'irb', '~> 1.15.1', require: false
gem 'rspec', '~> 3.13.0', require: false
gem 'rspec_junit_formatter', '~> 0.6.0', require: false
gem 'simplecov-cobertura', '~> 2.1.0', require: false
gem 'webmock', '~> 3.25', require: false
end
group :development, :test, :danger do
gem 'gitlab-dangerfiles', '~> 4.8.1', require: false
gem 'resolv', '~> 0.6.0', require: false
gem 'ruby-lsp', "~> 0.23.0", require: false
gem 'ruby-lsp-rspec', "~> 0.1.10", require: false
end
PATH
remote: gem
specs:
gitlab-development-kit (0.2.19)
gitlab-sdk (~> 0.3.1)
rake (~> 13.1)
sentry-ruby (~> 5.23)
tty-markdown (~> 0.7.2)
tty-spinner (~> 0.9.3)
zeitwerk (~> 2.6.15)
GEM
remote: https://rubygems.org/
specs:
activesupport (7.1.3.4)
base64
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0)
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
ast (2.4.2)
base64 (0.2.0)
bigdecimal (3.1.8)
byebug (11.1.3)
claide (1.1.0)
claide-plugins (0.9.2)
cork
nap
open4 (~> 1.3)
coderay (1.1.3)
colored2 (3.1.2)
concurrent-ruby (1.3.3)
connection_pool (2.4.1)
cork (0.3.0)
colored2 (~> 3.1)
crack (1.0.0)
bigdecimal
rexml
csv (3.3.0)
danger (9.4.3)
claide (~> 1.0)
claide-plugins (>= 0.9.2)
colored2 (~> 3.1)
cork (~> 0.1)
faraday (>= 0.9.0, < 3.0)
faraday-http-cache (~> 2.0)
git (~> 1.13)
kramdown (~> 2.3)
kramdown-parser-gfm (~> 1.0)
no_proxy_fix
octokit (>= 4.0)
terminal-table (>= 1, < 4)
danger-gitlab (8.0.0)
danger
gitlab (~> 4.2, >= 4.2.0)
diff-lcs (1.5.1)
docile (1.4.0)
drb (2.2.1)
faraday (2.9.2)
faraday-net_http (>= 2.0, < 3.2)
faraday-http-cache (2.5.1)
faraday (>= 0.8)
faraday-net_http (3.1.0)
net-http
git (1.19.1)
addressable (~> 2.8)
rchardet (~> 1.8)
gitlab (4.20.1)
httparty (~> 0.20)
terminal-table (>= 1.5.1)
gitlab-dangerfiles (4.8.1)
danger (>= 9.3.0)
danger-gitlab (>= 8.0.0)
rake (~> 13.0)
gitlab-sdk (0.3.1)
activesupport (>= 5.2.0)
rake (~> 13.0)
snowplow-tracker (~> 0.8.0)
gitlab-styles (13.0.2)
rubocop (~> 1.68.0)
rubocop-capybara (~> 2.21.0)
rubocop-factory_bot (~> 2.26.1)
rubocop-graphql (~> 1.5.4)
rubocop-performance (~> 1.21.1)
rubocop-rails (~> 2.26.0)
rubocop-rspec (~> 3.0.4)
rubocop-rspec_rails (~> 2.30.0)
hashdiff (1.1.1)
httparty (0.22.0)
csv
mini_mime (>= 1.0.0)
multi_xml (>= 0.5.2)
i18n (1.14.5)
concurrent-ruby (~> 1.0)
io-console (0.7.2)
irb (1.15.1)
pp (>= 0.6.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
json (2.7.2)
kramdown (2.4.0)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
language_server-protocol (3.17.0.3)
lefthook (1.10.10)
logger (1.6.6)
method_source (1.0.0)
mini_mime (1.1.5)
minitest (5.24.1)
multi_xml (0.7.1)
bigdecimal (~> 3.1)
mutex_m (0.2.0)
nap (1.1.0)
net-http (0.4.1)
uri
no_proxy_fix (0.1.2)
octokit (6.1.1)
faraday (>= 1, < 3)
sawyer (~> 0.9)
open4 (1.3.4)
parallel (1.25.1)
parser (3.3.3.0)
ast (~> 2.4.1)
racc
pastel (0.8.0)
tty-color (~> 0.5)
pp (0.6.2)
prettyprint
prettyprint (0.2.0)
prism (1.3.0)
pry (0.14.2)
coderay (~> 1.1)
method_source (~> 1.0)
pry-byebug (3.10.1)
byebug (~> 11.0)
pry (>= 0.13, < 0.15)
psych (5.1.2)
stringio
public_suffix (5.1.1)
racc (1.8.0)
rack (3.1.8)
rainbow (3.1.1)
rake (13.2.1)
rbs (3.8.1)
logger
rchardet (1.8.0)
rdoc (6.6.3.1)
psych (>= 4.0.0)
regexp_parser (2.9.2)
reline (0.5.9)
io-console (~> 0.5)
resolv (0.6.0)
rexml (3.3.1)
strscan
rouge (4.4.0)
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.0)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.0)
rspec_junit_formatter (0.6.0)
rspec-core (>= 2, < 4, != 2.12.0)
rubocop (1.68.0)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.4, < 3.0)
rubocop-ast (>= 1.32.2, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.32.3)
parser (>= 3.3.1.0)
rubocop-capybara (2.21.0)
rubocop (~> 1.41)
rubocop-factory_bot (2.26.1)
rubocop (~> 1.61)
rubocop-graphql (1.5.4)
rubocop (>= 1.50, < 2)
rubocop-performance (1.21.1)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rails (2.26.2)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.52.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rake (0.6.0)
rubocop (~> 1.0)
rubocop-rspec (3.0.5)
rubocop (~> 1.61)
rubocop-rspec_rails (2.30.0)
rubocop (~> 1.61)
rubocop-rspec (~> 3, >= 3.0.1)
ruby-lsp (0.23.11)
language_server-protocol (~> 3.17.0)
prism (>= 1.2, < 2.0)
rbs (>= 3, < 4)
sorbet-runtime (>= 0.5.10782)
ruby-lsp-rspec (0.1.22)
ruby-lsp (~> 0.23.0)
ruby-progressbar (1.13.0)
sawyer (0.9.2)
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
sentry-ruby (5.23.0)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
simplecov (0.21.2)
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
simplecov-cobertura (2.1.0)
rexml
simplecov (~> 0.19)
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.4)
snowplow-tracker (0.8.0)
sorbet-runtime (0.5.11911)
stringio (3.1.1)
strings (0.2.1)
strings-ansi (~> 0.2)
unicode-display_width (>= 1.5, < 3.0)
unicode_utils (~> 1.4)
strings-ansi (0.2.0)
strscan (3.1.0)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
tty-color (0.6.0)
tty-cursor (0.7.1)
tty-markdown (0.7.2)
kramdown (>= 1.16.2, < 3.0)
pastel (~> 0.8)
rouge (>= 3.14, < 5.0)
strings (~> 0.2.0)
tty-color (~> 0.5)
tty-screen (~> 0.8)
tty-screen (0.8.2)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.5.0)
unicode_utils (1.4.0)
uri (0.13.0)
webmock (3.25.0)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
yard (0.9.37)
zeitwerk (2.6.15)
PLATFORMS
ruby
DEPENDENCIES
gitlab-dangerfiles (~> 4.8.1)
gitlab-development-kit!
gitlab-styles (~> 13.0.2)
irb (~> 1.15.1)
lefthook (~> 1.10.10)
pry-byebug
resolv (~> 0.6.0)
rspec (~> 3.13.0)
rspec_junit_formatter (~> 0.6.0)
rubocop
rubocop-rake (~> 0.6.0)
ruby-lsp (~> 0.23.0)
ruby-lsp-rspec (~> 0.1.10)
simplecov-cobertura (~> 2.1.0)
webmock (~> 3.25)
yard (~> 0.9.37)
BUNDLED WITH
2.6.5
# frozen_string_literal: true
$LOAD_PATH.unshift(File.expand_path('lib', __dir__))
require 'gitlab_development_kit'
Gem::Specification.new do |spec|
spec.name = 'gitlab-development-kit'
spec.version = GDK::GEM_VERSION
spec.authors = ['Jacob Vosmaer', 'GitLab']
spec.email = ['[email protected]']
spec.summary = 'CLI for GitLab Development Kit'
spec.description = 'CLI for GitLab Development Kit.'
spec.homepage = 'https://gitlab.com/gitlab-org/gitlab-development-kit'
spec.license = 'MIT'
spec.files = ['lib/gitlab_development_kit.rb']
spec.executables = ['gdk']
spec.required_ruby_version = '>= 3.2.0'
spec.metadata['rubygems_mfa_required'] = 'true'
spec.add_dependency 'gitlab-sdk', '~> 0.3.1'
spec.add_dependency 'rake', '~> 13.1'
spec.add_dependency 'sentry-ruby', '~> 5.23'
spec.add_dependency 'tty-markdown', '~> 0.7.2'
spec.add_dependency 'tty-spinner', '~> 0.9.3'
spec.add_dependency 'zeitwerk', '~> 2.6.15'
end
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
slapd 87537 $USER 7u IPv4 209293 0t0 TCP krb5.gdk.test:3890 (LISTEN)
gitlab-wo 87621 $USER 6u IPv4 204708 0t0 TCP krb5.gdk.test:3333 (LISTEN)
gitlab-wo 87621 $USER 7u IPv4 204709 0t0 TCP krb5.gdk.test:40879 (LISTEN)
nginx 87625 $USER 5u IPv4 206417 0t0 TCP krb5.gdk.test:http-alt (LISTEN)
gitlab-ss 87626 $USER 6u IPv4 184649 0t0 TCP krb5.gdk.test:2222 (LISTEN)
nginx 87646 $USER 5u IPv4 206417 0t0 TCP krb5.gdk.test:http-alt (LISTEN)
topology- 88002 $USER 3u IPv6 204724 0t0 TCP *:9095 (LISTEN)
topology- 88002 $USER 6u IPv6 204726 0t0 TCP *:9096 (LISTEN)
webpack 88043 $USER 18u IPv4 209310 0t0 TCP krb5.gdk.test:3808 (LISTEN)
node 88070 $USER 28u IPv4 208199 0t0 TCP krb5.gdk.test:39551 (LISTEN)
node 88070 $USER 35u IPv4 212360 0t0 TCP krb5.gdk.test:45511 (LISTEN)
workerd 88337 $USER 12u IPv4 212345 0t0 TCP krb5.gdk.test:46651 (LISTEN)
workerd 88337 $USER 13u IPv4 212347 0t0 TCP krb5.gdk.test:9229 (LISTEN)
workerd 88337 $USER 14u IPv4 212349 0t0 TCP krb5.gdk.test:3443 (LISTEN)
workerd 88402 $USER 14u IPv4 25749 0t0 TCP krb5.gdk.test:34781 (LISTEN)
workerd 88402 $USER 16u IPv4 204755 0t0 TCP krb5.gdk.test:41983 (LISTEN)
workerd 88402 $USER 17u IPv4 204757 0t0 TCP krb5.gdk.test:37175 (LISTEN)
Git Status:
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
Git HEAD:
commit aac934e0242ef46ac53f74cf3e16e5c1e326312e
Git Status:
HEAD detached at 55f4fb94e
nothing to commit, working tree clean
Git HEAD:
commit 55f4fb94e39f60e1d4c76deac5d6f20c6202c68f
Git Status:
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
Git HEAD:
commit ac0a217c721258e11c0aa11fe22a48a46d854d6c
Created at: 13/06/2025 00:44:14 EEST
Bogdan Denkovych (debf7240) at 17 Mar 13:36
Bogdan Denkovych (3fbbe9ea) at 17 Mar 13:36
Merge branch '20184-gpat-on-credentials' into 'master'
... and 1 more commit
Credentials pageFeature.enable(:granular_personal_access_tokens)
Preferences > Personal access tokens.Admin area and navigate to Credentials to see the token.Feature.disable(:granular_personal_access_tokens)
Inactive warning message.Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to gitlab-org#20184
Implements three Rake tasks for managing Email OTP enrollment, in support of mandatory Email OTP enforcement on GitLab.com and, for those that want it, eventually on self-managed instances. Closes #589173.
gitlab:email_otp:enrol — Sets email_otp_required_after in bulk for all in-scope users. Defaults to DRY_RUN=true so it can be used safely to count affected users before committing.
Supports three operational modes:
| Mode | Parameters | Effect |
|---|---|---|
| Enrol new users | ENROL_AT=<date> |
Sets enrollment date for all in-scope users not yet enrolled |
| Shift a cohort | ENROL_AT=<new_date> EXISTING_ENROL_AT=<old_date> |
Moves a specific cohort to a new date |
| Revert a cohort | EXISTING_ENROL_AT=<old_date> |
Clears enrollment for a specific cohort (sets to NULL) |
The latter two in particular can be used to rollback / revert an enrolment.
gitlab:email_otp:enforce — Enables require_minimum_email_based_otp_for_users_with_passwords instance setting.
gitlab:email_otp:unenforce — Disables the same setting.
A user is in scope for new enrollment when all of the following are true:
users.state = 'active' and users.user_type = 0 (human, non-bot)users.password_automatically_set = false (self-set password)users.otp_required_for_login = false (no TOTP)authentication_mode = 2 (second-factor)user_details.email_otp_required_after IS NULL (not already enrolled)# 1. Dry-run to see how many users are in scope
bundle exec rake gitlab:email_otp:enrol ENROL_AT=2027-01-01T00:00:00Z
# 2. Enrol for real
bundle exec rake gitlab:email_otp:enrol DRY_RUN=false ENROL_AT=2027-01-01T00:00:00Z
# 3. Confirm count is now 0
bundle exec rake gitlab:email_otp:enrol ENROL_AT=2027-01-01T00:00:00Z
# 4. Enable enforcement
bundle exec rake gitlab:email_otp:enforce
For rollback or date-shifting a cohort:
# Shift cohort
bundle exec rake gitlab:email_otp:enrol DRY_RUN=false ENROL_AT=2027-02-01T00:00:00Z EXISTING_ENROL_AT=2027-01-01T00:00:00Z
# Revert cohort to unenrolled
bundle exec rake gitlab:email_otp:enrol DRY_RUN=false EXISTING_ENROL_AT=2027-01-01T00:00:00Z
My GDK has a tiny number of rows, but to give a sense of the script output:
% ENROL_AT="2027-01-01T01:02:03Z" DRY_RUN=true bundle exec rake gitlab:email_otp:enrol
Dry Run: Yes
Setting enrollment date: 2027-01-01 01:02:03 UTC
Applying to existing enrollment date (target cohort):
Batch Size: 1000
Sleep between batches: 0s
Feature Flag (:email_based_mfa) enabled: Yes
Is this correct? yes
[2026-02-24T03:42:01Z][DRY RUN] Enrolling users...
[2026-02-24T03:42:01Z][DRY RUN] Batch 1: 20 rows updated (cumulative: 20)
[2026-02-24T03:42:01Z][DRY RUN] ✓ Enrollment complete. Total users enrolled: 20
% ENROL_AT="2027-01-01T01:02:03Z" DRY_RUN=false bundle exec rake gitlab:email_otp:enrol
Dry Run: No
Setting enrollment date: 2027-01-01 01:02:03 UTC
Applying to existing enrollment date (target cohort):
Batch Size: 1000
Sleep between batches: 0.1s
Feature Flag (:email_based_mfa) enabled: Yes
Is this correct? yes
[2026-02-24T03:42:31Z] Enrolling users...
[2026-02-24T03:42:31Z] Batch 1: 20 rows updated (cumulative: 20)
[2026-02-24T03:42:31Z] ✓ Enrollment complete. Total users enrolled: 20
[1] pry(main)> UserDetail.where(email_otp_required_after: '2027-01-01T01:02:03Z').count
UserDetail Count (1.3ms) SELECT COUNT(*) FROM "user_details" WHERE "user_details"."email_otp_required_after" = '2027-01-01 01:02:03'
=> 20
% EXISTING_ENROL_AT="2027-01-01T01:02:03Z" DRY_RUN=false bundle exec rake gitlab:email_otp:enrol
Dry Run: No
Setting enrollment date:
Applying to existing enrollment date (target cohort): 2027-01-01 01:02:03 UTC
Batch Size: 1000
Sleep between batches: 0.1s
Feature Flag (:email_based_mfa) enabled: Yes
Is this correct? yes
[2026-02-24T03:43:07Z] Enrolling users...
[2026-02-24T03:43:07Z] Batch 1: 20 rows updated (cumulative: 20)
[2026-02-24T03:43:07Z] ✓ Enrollment complete. Total users enrolled: 20
[2] pry(main)> UserDetail.where(email_otp_required_after: '2027-01-01T01:02:03Z').count
UserDetail Count (0.6ms) SELECT COUNT(*) FROM "user_details" WHERE "user_details"."email_otp_required_after" = '2027-01-01 01:02:03'
=> 0
each_batch is the GitLab way of creating batches, and scans over windows as follows (4427 is a random user ID):
SELECT "users"."id" FROM "users" WHERE "users"."state" = 'active' AND "users"."user_type" IN (0, 6, 4, 13) AND "users"."user_type" = 0 AND "users"."id" >= 4427 ORDER BY "users"."id" ASC LIMIT 1 OFFSET 1000
The performance of that query is straightforward and can be seen at https://console.postgres.ai/gitlab/gitlab-production-main/sessions/49251/commands/146968
A materialised view is used to operate over each_batch:
WITH batch AS MATERIALIZED (SELECT "users"."id", "users"."password_automatically_set", "users"."otp_required_for_login" FROM "users" WHERE "users"."state" = 'active' AND "users"."user_type" IN (0, 6, 4, 13) AND "users"."user_type" = 0 AND "users"."id" >= REDACTED AND "users"."id" < REDACTED LIMIT 1000),
filtered_batch AS MATERIALIZED (
SELECT id FROM batch
WHERE password_automatically_set IS NOT TRUE
AND otp_required_for_login IS NOT TRUE
LIMIT 1000
),
without_webauthn AS MATERIALIZED (
SELECT filtered_batch.id FROM filtered_batch
LEFT JOIN webauthn_registrations ON webauthn_registrations.user_id = filtered_batch.id
AND webauthn_registrations.authentication_mode = 2
WHERE webauthn_registrations.user_id IS NULL
LIMIT 1000
)
UPDATE user_details SET email_otp_required_after = '2027-01-02 03:04:05'
WHERE user_id IN (SELECT id FROM without_webauthn) AND email_otp_required_after IS NULL
https://console.postgres.ai/gitlab/gitlab-production-main/sessions/49564/commands/147734
Note that PostgresAI says "Query returned 0 rows. This may not reflect production performance or use the same query plan. If you expect results, try adjusting parameters (e.g., different ID values)." However I believe the "Trigger ... calls=XXXX" at the end indicates the number of records that would be updated.
WITH batch AS MATERIALIZED (
SELECT "users"."id", "users"."password_automatically_set", "users"."otp_required_for_login"
FROM "users"
WHERE "users"."state" = 'active'
AND "users"."user_type" IN (0, 6, 4, 13)
AND "users"."user_type" = 0
AND "users"."id" >= REDACTED
AND "users"."id" < REDACTED
LIMIT 1000)
UPDATE user_details SET email_otp_required_after = '2026-04-06 20:01:02'
WHERE user_id IN (SELECT id FROM batch) AND email_otp_required_after = '2026-04-06 20:00:00'
This task is somewhat similar to the token expiry management task in that it's authentication & date related, and iterates many records using each_batch.
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
BATCH_SLEEP default is tunable, script is safely interruptible and re-runnable, replication lag guidance linked in code comments.email_based_mfa remains default-disabled, I think it is appropriate to not document it at https://docs.gitlab.com/administration/raketasks/
@gitlab-com/gl-security/appsec."Create the data layer for Terraform state protection rules, enabling project maintainers to define rules that restrict who can write to a Terraform state based on project role and request source (PAT, CI job, CI on protected branch).
This is the foundational MR (1 of 7) for the protected Terraform states feature. It creates the terraform_state_protection_rules database table and the Terraform::StateProtectionRule model following the packages_protection_rules pattern.
What's included:
terraform_state_protection_rules with:
project_id FK (cascade delete)state_name (text, max 255 chars) — exact match against Terraform state nameminimum_access_level_for_write (smallint enum: developer, maintainer, owner, admin)allowed_from (smallint enum: anywhere, ci_only, ci_on_protected_branch_only)(project_id, state_name)
Terraform::StateProtectionRule) with enums using Gitlab::Access constants, validations, and for_state_name scopehas_many :terraform_state_protection_rules
No behavior changes yet — rules can only be created via Rails console. Enforcement, CRUD services, API endpoints, and UI follow in subsequent MRs.
packages_protection_rules
Not applicable — backend-only changes.
bundle exec rails db:migrate
project = Project.first
rule = project.terraform_state_protection_rules.create!(
state_name: 'production',
minimum_access_level_for_write: :maintainer,
allowed_from: :ci_only
)
ActiveRecord::RecordInvalid
project.terraform_state_protection_rules returns the created rulesTerraform::StateProtectionRule.for_state_name('production') returns matching rulesPlease evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Credentials pageFeature.enable(:granular_personal_access_tokens)
Preferences > Personal access tokens.Admin area and navigate to Credentials to see the token.Feature.disable(:granular_personal_access_tokens)
Inactive warning message.Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to gitlab-org#20184
During review:
db:gitlabcom-database-testing job and reviewed its output gitlab-org/gitlab!225580 (comment 3155212947).Post-review:
@bmarjanovic please add feedback, and compare this review to the average maintainer review.
@bmarjanovic Could you please provide database maintainer review?
@gerardo-navarro This MR LGTM from database perspective. I left a few backend suggestions.
Let's also add spec for this in spec/models/project_spec.rb.
As per suggestion to remove for_state_name scope.
Rails scopes always return a collection. Since a project cannot have multiple terraform_state_protection_rules with the same state_name, we will probably rely on Rails find_by_* method, like project.terraform_state_protection_rules.find_by_state_name. Let's remove this scope?
If we wanted to really accurate (and it might be overkill unless the FF stays in the system longer)
I agree.
To correctly disable granular token for authentication by the FF, it should be checked in
PersonalAccessToken.find_by_tokenmethod for the related user instead.
I think this is important.
Credentials pageFeature.enable(:granular_personal_access_tokens)
Preferences > Personal access tokens.Admin area and navigate to Credentials to see the token.Feature.disable(:granular_personal_access_tokens)
Inactive warning message.Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to gitlab-org#20184
Changes in this file may conflict with !227027 (merged). Let's revert all changes in this file for this MR?
Revert "Merge branch '589499-show-gpat-as-inactive' into 'master'"
This reverts merge request !224006
https://gitlab.com/gitlab-org/gitlab/-/work_items/592892
| Before | After |
|---|---|
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
We should keep this feature_category to make CI pass.
RSpec.describe API::Entities::PersonalAccessToken, feature_category: :system_access do@hmehra @alexbuijs See !222002 (comment 3150702867).
I skimmed over the existing granular_personal_access_tokens FF checks. It looks like we incorrectly apply granular_personal_access_tokens FF. We should check granular_personal_access_tokens for current_user only for creating token and for user_settings pages. In other cases, the FF should be checked for personal_access_token.user. Correct?
What concerns me the most is the FF check in https://gitlab.com/gitlab-org/gitlab/-/blob/607bbb317dbf996e515315033ea67170b8065318/app/finders/personal_access_tokens_finder.rb#L81. There is no guarantee that current_user is always present in that context, for instance see https://gitlab.com/gitlab-org/gitlab/-/blob/607bbb317dbf996e515315033ea67170b8065318/lib/gitlab/auth.rb#L301-L304. Meaning that currently the FF could allow users manage granular tokens, but they won't be able to use them/authenticate with them until the FF is globally enabled.
To correctly disable granular token for authentication by the FF, it should be checked in PersonalAccessToken.find_by_token method for the related user instead.