Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-08-07 15:08:06 +00:00
parent 4593ad2e15
commit 755df8c847
150 changed files with 1738 additions and 1131 deletions

View File

@ -9,6 +9,9 @@
## Allows release tooling and Gitaly team members to update the Gitaly Version ## Allows release tooling and Gitaly team members to update the Gitaly Version
/GITALY_SERVER_VERSION @project_278964_bot6 @gitlab-org/maintainers/rails-backend @gitlab-org/delivery @gl-gitaly /GITALY_SERVER_VERSION @project_278964_bot6 @gitlab-org/maintainers/rails-backend @gitlab-org/delivery @gl-gitaly
## Allows release tooling, KAS version maintainers and the delivery team to update the KAS version
/GITLAB_KAS_VERSION @project_278964_bot6 @gitlab-org/maintainers/kas-version-maintainers @gitlab-org/maintainers/rails-backend @gitlab-org/delivery
## Files that are excluded from required approval ## Files that are excluded from required approval
## These rules override the * rule above, so that changes to docs and templates ## These rules override the * rule above, so that changes to docs and templates
## can be merged by any user who has maintainer rights, but is not included in ## can be merged by any user who has maintainer rights, but is not included in
@ -1565,9 +1568,6 @@ ee/lib/ee/api/entities/project.rb
/ee/lib/arkose/ /ee/lib/arkose/
/ee/lib/telesign/ /ee/lib/telesign/
[Deploy:Environments - KAS Version Maintainers] @project_278964_bot6 @gitlab-org/maintainers/kas-version-maintainers @gitlab-org/maintainers/rails-backend @gitlab-org/delivery
/GITLAB_KAS_VERSION
^[DiffMatchPatch gem] ^[DiffMatchPatch gem]
/vendor/gems/diff_match_patch @garyh /vendor/gems/diff_match_patch @garyh

View File

@ -390,7 +390,6 @@ Layout/EmptyLineAfterMagicComment:
- 'spec/components/pajamas/avatar_component_spec.rb' - 'spec/components/pajamas/avatar_component_spec.rb'
- 'spec/components/pajamas/banner_component_spec.rb' - 'spec/components/pajamas/banner_component_spec.rb'
- 'spec/components/pajamas/button_component_spec.rb' - 'spec/components/pajamas/button_component_spec.rb'
- 'spec/components/pajamas/card_component_spec.rb'
- 'spec/components/pajamas/checkbox_component_spec.rb' - 'spec/components/pajamas/checkbox_component_spec.rb'
- 'spec/components/pajamas/checkbox_tag_component_spec.rb' - 'spec/components/pajamas/checkbox_tag_component_spec.rb'
- 'spec/components/pajamas/component_spec.rb' - 'spec/components/pajamas/component_spec.rb'
@ -403,7 +402,6 @@ Layout/EmptyLineAfterMagicComment:
- 'spec/components/previews/pajamas/avatar_component_preview.rb' - 'spec/components/previews/pajamas/avatar_component_preview.rb'
- 'spec/components/previews/pajamas/banner_component_preview.rb' - 'spec/components/previews/pajamas/banner_component_preview.rb'
- 'spec/components/previews/pajamas/button_component_preview.rb' - 'spec/components/previews/pajamas/button_component_preview.rb'
- 'spec/components/previews/pajamas/card_component_preview.rb'
- 'spec/components/previews/pajamas/spinner_component_preview.rb' - 'spec/components/previews/pajamas/spinner_component_preview.rb'
- 'spec/controllers/application_controller_spec.rb' - 'spec/controllers/application_controller_spec.rb'
- 'spec/controllers/projects/jobs_controller_spec.rb' - 'spec/controllers/projects/jobs_controller_spec.rb'

View File

@ -876,7 +876,6 @@ RSpec/ContextWording:
- 'spec/components/pajamas/alert_component_spec.rb' - 'spec/components/pajamas/alert_component_spec.rb'
- 'spec/components/pajamas/banner_component_spec.rb' - 'spec/components/pajamas/banner_component_spec.rb'
- 'spec/components/pajamas/button_component_spec.rb' - 'spec/components/pajamas/button_component_spec.rb'
- 'spec/components/pajamas/card_component_spec.rb'
- 'spec/components/pajamas/spinner_component_spec.rb' - 'spec/components/pajamas/spinner_component_spec.rb'
- 'spec/config/object_store_settings_spec.rb' - 'spec/config/object_store_settings_spec.rb'
- 'spec/controllers/admin/application_settings_controller_spec.rb' - 'spec/controllers/admin/application_settings_controller_spec.rb'

View File

@ -1192,7 +1192,6 @@ RSpec/FeatureCategory:
- 'spec/components/pajamas/badge_component_spec.rb' - 'spec/components/pajamas/badge_component_spec.rb'
- 'spec/components/pajamas/banner_component_spec.rb' - 'spec/components/pajamas/banner_component_spec.rb'
- 'spec/components/pajamas/button_component_spec.rb' - 'spec/components/pajamas/button_component_spec.rb'
- 'spec/components/pajamas/card_component_spec.rb'
- 'spec/components/pajamas/checkbox_component_spec.rb' - 'spec/components/pajamas/checkbox_component_spec.rb'
- 'spec/components/pajamas/checkbox_tag_component_spec.rb' - 'spec/components/pajamas/checkbox_tag_component_spec.rb'
- 'spec/components/pajamas/component_spec.rb' - 'spec/components/pajamas/component_spec.rb'

View File

@ -781,7 +781,6 @@ Style/IfUnlessModifier:
- 'scripts/setup/find-jh-branch.rb' - 'scripts/setup/find-jh-branch.rb'
- 'scripts/static-analysis' - 'scripts/static-analysis'
- 'spec/components/previews/pajamas/alert_component_preview.rb' - 'spec/components/previews/pajamas/alert_component_preview.rb'
- 'spec/components/previews/pajamas/card_component_preview.rb'
- 'spec/factories/ci/runners.rb' - 'spec/factories/ci/runners.rb'
- 'spec/factories/container_repositories.rb' - 'spec/factories/container_repositories.rb'
- 'spec/factories/deployments.rb' - 'spec/factories/deployments.rb'

View File

@ -2,6 +2,38 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 17.2.2 (2024-08-06)
### Fixed (2 changes)
- [bug: Fix template error due to divided by zero](https://gitlab.com/gitlab-org/security/gitlab/-/commit/a09aab977c287262a07bec5a267d611c56bf4f9c)
- [Ignore unknown sequences in sequence fix migration](https://gitlab.com/gitlab-org/security/gitlab/-/commit/7aa835983a46af9edd1ac4699593017e66979e1d)
### Changed (2 changes)
- [Reverify externally verified gpg keys](https://gitlab.com/gitlab-org/security/gitlab/-/commit/a390e0347e8bd5565d6c324c82221a0f7cccedfc)
- [Put groups_direct field in CI JWT tokens behind feature flag](https://gitlab.com/gitlab-org/security/gitlab/-/commit/59f2133beed57e99c0f8ebab31ea77bb892fef36)
### Security (13 changes)
- [Show correct file content](https://gitlab.com/gitlab-org/security/gitlab/-/commit/1357224fea289ba708f30f528c04e213b29e0b23) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4334))
- [Fix Possible asciidoctor include:: directive DOS](https://gitlab.com/gitlab-org/security/gitlab/-/commit/9762e4636b3dd69edac8b235b4706db515e65e79) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4329))
- [Filter parameters in Rack::Attack logs](https://gitlab.com/gitlab-org/security/gitlab/-/commit/401bdc5202d7b083f750361a2f1ef57466bc919f) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4272))
- [Update audit payload](https://gitlab.com/gitlab-org/security/gitlab/-/commit/864194bebe8a5b2e2187d04a65e0e2b530c7b779) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4325))
- [Limit access to project accessed by Security Policy Bot](https://gitlab.com/gitlab-org/security/gitlab/-/commit/100a915754d858cd18cfb7851c80944c8fda640b) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4343))
- [Show alert about not rendering files due to path encoding](https://gitlab.com/gitlab-org/security/gitlab/-/commit/d8533d727a1c036560df59282bf62ab561258a13) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4337))
- [Fix the catastrophic backtracking](https://gitlab.com/gitlab-org/security/gitlab/-/commit/001aab470cfc14b4c1655de2382d0aa4c39a4fac) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4289))
- [Security fixes for banzai pipeline part 2](https://gitlab.com/gitlab-org/security/gitlab/-/commit/266c315f6e825881c36aa78f0203bf6a2c36a132) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4283))
- [Remove xhtml extensions from snippets blobs](https://gitlab.com/gitlab-org/security/gitlab/-/commit/73b5fc95468dcc35d796737ebb1a6c11d88ebf64) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4300))
- [Add a project scope to LfsTokens](https://gitlab.com/gitlab-org/security/gitlab/-/commit/943c7867ce0d9dc98929af322ecd422438c9f9c6) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4319))
- [Fix ReDoS when parsing git push options](https://gitlab.com/gitlab-org/security/gitlab/-/commit/798466f7574554358d770d28df036f60eff31e41) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4312))
- [Fix ReDoS in RefMatcher](https://gitlab.com/gitlab-org/security/gitlab/-/commit/87d308caed2a1ec7f5ae7ddc1131f5c7abbffdbd) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4315))
- [Enforce `require_password_to_approve` MR approval policy property](https://gitlab.com/gitlab-org/security/gitlab/-/commit/129139c6eebd257bc5eae142c52267bb83a71307) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4277))
### Other (1 change)
- [Introduce lock-free rescheduling for duplicate job](https://gitlab.com/gitlab-org/security/gitlab/-/commit/9a15c696b06e4240b02bc54b0c36ed10450c7244)
## 17.2.1 (2024-07-24) ## 17.2.1 (2024-07-24)
### Fixed (1 change) ### Fixed (1 change)
@ -791,6 +823,29 @@ entry.
- [Remove "use_remote_mirror_destroy_service" feature flag](https://gitlab.com/gitlab-org/gitlab/-/commit/74e1e921d003960afd6f259384aee2dfec18f30e) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/155852)) - [Remove "use_remote_mirror_destroy_service" feature flag](https://gitlab.com/gitlab-org/gitlab/-/commit/74e1e921d003960afd6f259384aee2dfec18f30e) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/155852))
- [Protected containers: Cleanup renaming of protected_up_to_access_level](https://gitlab.com/gitlab-org/gitlab/-/commit/4606b5ef64f75acdd581258a0b93034195626e83) by @gerardo-navarro ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/146177)) - [Protected containers: Cleanup renaming of protected_up_to_access_level](https://gitlab.com/gitlab-org/gitlab/-/commit/4606b5ef64f75acdd581258a0b93034195626e83) by @gerardo-navarro ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/146177))
## 17.1.4 (2024-08-06)
### Changed (2 changes)
- [Reverify externally verified gpg keys](https://gitlab.com/gitlab-org/security/gitlab/-/commit/e11bfa6bdfcf0b40f440bf50e104d5d4e4496d74)
- [Put groups_direct field in CI JWT tokens behind feature flag](https://gitlab.com/gitlab-org/security/gitlab/-/commit/024945347ea0b433de65c0ecb80c50cc031cbc52)
### Security (13 changes)
- [Show correct file content](https://gitlab.com/gitlab-org/security/gitlab/-/commit/59df2cc3758c03aff024151f5dfd59fa3263ac7b) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4335))
- [Fix Possible asciidoctor include:: directive DOS](https://gitlab.com/gitlab-org/security/gitlab/-/commit/6fcbfba6119fcadff61dc4550d244b56f5fe6c70) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4330))
- [Filter parameters in Rack::Attack logs](https://gitlab.com/gitlab-org/security/gitlab/-/commit/9b807312a2029e6a341962591dcdcfd21ea8ef0c) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4273))
- [Update audit payload](https://gitlab.com/gitlab-org/security/gitlab/-/commit/7beb230f12ec6270523a269dad39dba42fdc108e) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4326))
- [Limit access to project accessed by Security Policy Bot](https://gitlab.com/gitlab-org/security/gitlab/-/commit/b58cad5e32c2b9f399742719006a4e527f773e2d) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4344))
- [Show alert about not rendering files due to path encoding](https://gitlab.com/gitlab-org/security/gitlab/-/commit/274a7177f5eea11e258534e5155f878334bf48ca) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4338))
- [Fix the catastrophic backtracking](https://gitlab.com/gitlab-org/security/gitlab/-/commit/88e2d71de74d04e29a8a62527bb147208c86fc29) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4290))
- [Security fixes for banzai pipeline part 2](https://gitlab.com/gitlab-org/security/gitlab/-/commit/8167c0e9225c5893043ea34bfc1353035f173924) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4282))
- [Remove xhtml extensions from snippets blobs](https://gitlab.com/gitlab-org/security/gitlab/-/commit/8ba1a3f5a36820995e512b4ec846d57df54ed9c4) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4301))
- [Add a project scope to LfsTokens](https://gitlab.com/gitlab-org/security/gitlab/-/commit/9e684758e31af25bdb69a8d4f95e8e0821bfc40b) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4320))
- [Fix ReDoS when parsing git push options](https://gitlab.com/gitlab-org/security/gitlab/-/commit/f49a979105bdfd365738d42406e94f7cabba4601) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4313))
- [Fix ReDoS in RefMatcher](https://gitlab.com/gitlab-org/security/gitlab/-/commit/ec18bbdcb19f831d3732e2ffebe87740982baf24) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4316))
- [Enforce `require_password_to_approve` MR approval policy property](https://gitlab.com/gitlab-org/security/gitlab/-/commit/d9769f6d7a11c2ae23f8816483358f7da3e729be) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4260))
## 17.1.3 (2024-07-24) ## 17.1.3 (2024-07-24)
### Fixed (2 changes) ### Fixed (2 changes)
@ -1950,6 +2005,28 @@ entry.
- [Update Web IDE dependency to receive duo fixes](gitlab-org/gitlab@47323c05565dd32ea4de9f999adbd9f7aa8748e3) ([merge request](gitlab-org/gitlab!154064)) - [Update Web IDE dependency to receive duo fixes](gitlab-org/gitlab@47323c05565dd32ea4de9f999adbd9f7aa8748e3) ([merge request](gitlab-org/gitlab!154064))
## 17.0.6 (2024-08-06)
### Changed (1 change)
- [Put groups_direct field in CI JWT tokens behind feature flag](https://gitlab.com/gitlab-org/security/gitlab/-/commit/106d8bbe3b70f99f52963ac363764f4eb6abd5c1)
### Security (13 changes)
- [Show correct file content](https://gitlab.com/gitlab-org/security/gitlab/-/commit/a1fa5a60d3f8b4d420e65baaf9eb631e2fa9bdf0) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4336))
- [Fix Possible asciidoctor include:: directive DOS](https://gitlab.com/gitlab-org/security/gitlab/-/commit/8d03c5769e39605f00c930d0fb7b9baab2b6ae5c) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4331))
- [Filter parameters in Rack::Attack logs](https://gitlab.com/gitlab-org/security/gitlab/-/commit/9ee1310ad76bceb5f45cb04ea4534c71efa90255) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4274))
- [Update audit payload](https://gitlab.com/gitlab-org/security/gitlab/-/commit/6e11e37c02cf10887a49e2ee494fec7efe37d944) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4327))
- [Limit access to project accessed by Security Policy Bot](https://gitlab.com/gitlab-org/security/gitlab/-/commit/3c4c9a4adf772993f42b4788303180d36fb8642d) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4345))
- [Show alert about not rendering files due to path encoding](https://gitlab.com/gitlab-org/security/gitlab/-/commit/d939235f3042ff0924e4a794cf0481bc28e08ae3) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4339))
- [Fix the catastrophic backtracking](https://gitlab.com/gitlab-org/security/gitlab/-/commit/7397896f34a4d0319a7750ae7f0a32aa2dad72c6) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4291))
- [Security fixes for banzai pipeline part 2](https://gitlab.com/gitlab-org/security/gitlab/-/commit/40cf9d179ad038363b59eb0accfd1fa2e6bef34b) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4281))
- [Remove xhtml extensions from snippets blobs](https://gitlab.com/gitlab-org/security/gitlab/-/commit/4952960acf3b3b133c29454375fcbb1e3850ee44) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4332))
- [Add a project scope to LfsTokens](https://gitlab.com/gitlab-org/security/gitlab/-/commit/cbe4a50b5844d452f12e58dab80143c7e548d273) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4321))
- [Fix ReDoS when parsing git push options](https://gitlab.com/gitlab-org/security/gitlab/-/commit/14b95bf425bf27746f73ec813753355919346b82) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4314))
- [Fix ReDoS in RefMatcher](https://gitlab.com/gitlab-org/security/gitlab/-/commit/fdab3bdb907212a736b961ed58f5ad4d52135108) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4317))
- [Enforce `require_password_to_approve` MR approval policy property](https://gitlab.com/gitlab-org/security/gitlab/-/commit/2d7c6114a6915143751f40e44ef2630647cf615a) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4261))
## 17.0.5 (2024-07-24) ## 17.0.5 (2024-07-24)
### Added (1 change) ### Added (1 change)

View File

@ -31,15 +31,15 @@
{"name":"ast","version":"2.4.2","platform":"ruby","checksum":"1e280232e6a33754cde542bc5ef85520b74db2aac73ec14acef453784447cc12"}, {"name":"ast","version":"2.4.2","platform":"ruby","checksum":"1e280232e6a33754cde542bc5ef85520b74db2aac73ec14acef453784447cc12"},
{"name":"async","version":"2.12.1","platform":"ruby","checksum":"146fb3acf6d05ad40abb9ae659dd3b574067a3420fe7d6d5d6a3cf5413de3ea5"}, {"name":"async","version":"2.12.1","platform":"ruby","checksum":"146fb3acf6d05ad40abb9ae659dd3b574067a3420fe7d6d5d6a3cf5413de3ea5"},
{"name":"atlassian-jwt","version":"0.2.1","platform":"ruby","checksum":"2fd2d87418773f2e140c038cb22e049069708aff2bd0a423a7e1740574e97823"}, {"name":"atlassian-jwt","version":"0.2.1","platform":"ruby","checksum":"2fd2d87418773f2e140c038cb22e049069708aff2bd0a423a7e1740574e97823"},
{"name":"attr_required","version":"1.0.1","platform":"ruby","checksum":"024e10393bd30901e1adf6769bd756b873a5ef7da60f86f8f11066116b5742bc"}, {"name":"attr_required","version":"1.0.2","platform":"ruby","checksum":"f0ebfc56b35e874f4d0ae799066dbc1f81efefe2364ca3803dc9ea6a4de6cb99"},
{"name":"awesome_print","version":"1.9.2","platform":"ruby","checksum":"e99b32b704acff16d768b3468680793ced40bfdc4537eb07e06a4be11133786e"}, {"name":"awesome_print","version":"1.9.2","platform":"ruby","checksum":"e99b32b704acff16d768b3468680793ced40bfdc4537eb07e06a4be11133786e"},
{"name":"awrence","version":"1.2.1","platform":"ruby","checksum":"dd1d214c12a91f449d1ef81d7ee3babc2816944e450752e7522c65521872483e"}, {"name":"awrence","version":"1.2.1","platform":"ruby","checksum":"dd1d214c12a91f449d1ef81d7ee3babc2816944e450752e7522c65521872483e"},
{"name":"aws-eventstream","version":"1.3.0","platform":"ruby","checksum":"f1434cc03ab2248756eb02cfa45e900e59a061d7fbdc4a9fd82a5dd23d796d3f"}, {"name":"aws-eventstream","version":"1.3.0","platform":"ruby","checksum":"f1434cc03ab2248756eb02cfa45e900e59a061d7fbdc4a9fd82a5dd23d796d3f"},
{"name":"aws-partitions","version":"1.877.0","platform":"ruby","checksum":"9552ed7bbd3700ed1eeb0121c160ceaf64fa5dbaff5a1ff5fe6fd8481ecd9cfd"}, {"name":"aws-partitions","version":"1.960.0","platform":"ruby","checksum":"0847ac5526305080ba6056d7f6b96c8d580d1526b79915d541333e58bf5ff857"},
{"name":"aws-sdk-cloudformation","version":"1.41.0","platform":"ruby","checksum":"31e47539719734413671edf9b1a31f8673fbf9688549f50c41affabbcb1c6b26"}, {"name":"aws-sdk-cloudformation","version":"1.41.0","platform":"ruby","checksum":"31e47539719734413671edf9b1a31f8673fbf9688549f50c41affabbcb1c6b26"},
{"name":"aws-sdk-core","version":"3.200.0","platform":"ruby","checksum":"1d9ac535f82b5ea7b3d6e0cee7be3c48981a948123a48ff755504b7343d16951"}, {"name":"aws-sdk-core","version":"3.201.3","platform":"ruby","checksum":"c045a7ff37b4a6f1de5742e64def0841bdf70d215cb17d3875b2c5bdd9e99d52"},
{"name":"aws-sdk-kms","version":"1.76.0","platform":"ruby","checksum":"e7f75013cba9ba357144f66bbc600631c192e2cda9dd572794be239654e2cf49"}, {"name":"aws-sdk-kms","version":"1.88.0","platform":"ruby","checksum":"13588d90df1eece81f6d79bd304b3857dc3168e7ea75c933b3b835cfe8a0e309"},
{"name":"aws-sdk-s3","version":"1.155.0","platform":"ruby","checksum":"4674e07846cc6d77d5bd122cef7fea5055e8b53bf238ab05beebc25ecb01c2e2"}, {"name":"aws-sdk-s3","version":"1.156.0","platform":"ruby","checksum":"9302da1d1a70363308854d5065035f6c72cf8b8af895d8789487cd5c6b076a46"},
{"name":"aws-sigv4","version":"1.8.0","platform":"ruby","checksum":"84dd99768b91b93b63d1d8e53ee837cfd06ab402812772a7899a78f9f9117cbc"}, {"name":"aws-sigv4","version":"1.8.0","platform":"ruby","checksum":"84dd99768b91b93b63d1d8e53ee837cfd06ab402812772a7899a78f9f9117cbc"},
{"name":"axe-core-api","version":"4.9.1","platform":"ruby","checksum":"9ea7ac16bfee1cb3545345d210878aa8cccfb41b493e00fe1faab79af4d9fed8"}, {"name":"axe-core-api","version":"4.9.1","platform":"ruby","checksum":"9ea7ac16bfee1cb3545345d210878aa8cccfb41b493e00fe1faab79af4d9fed8"},
{"name":"axe-core-rspec","version":"4.9.1","platform":"ruby","checksum":"31ef067bee36d6efb3f156a83aa2fb6ac721270a53fb9473f0268e325a3e6efd"}, {"name":"axe-core-rspec","version":"4.9.1","platform":"ruby","checksum":"31ef067bee36d6efb3f156a83aa2fb6ac721270a53fb9473f0268e325a3e6efd"},
@ -97,7 +97,7 @@
{"name":"creole","version":"0.5.0","platform":"ruby","checksum":"951701e2d80760f156b1cb2a93471ca97c076289becc067a33b745133ed32c03"}, {"name":"creole","version":"0.5.0","platform":"ruby","checksum":"951701e2d80760f156b1cb2a93471ca97c076289becc067a33b745133ed32c03"},
{"name":"crystalball","version":"0.7.0","platform":"ruby","checksum":"6e729f372a5071daec877adb40c5df4cb25fe21f350635e2a9624373fc151ef2"}, {"name":"crystalball","version":"0.7.0","platform":"ruby","checksum":"6e729f372a5071daec877adb40c5df4cb25fe21f350635e2a9624373fc151ef2"},
{"name":"css_parser","version":"1.14.0","platform":"ruby","checksum":"f2ce6148cd505297b07bdbe7a5db4cce5cf530071f9b732b9a23538d6cdc0113"}, {"name":"css_parser","version":"1.14.0","platform":"ruby","checksum":"f2ce6148cd505297b07bdbe7a5db4cce5cf530071f9b732b9a23538d6cdc0113"},
{"name":"cssbundling-rails","version":"1.4.0","platform":"ruby","checksum":"082034653af0ec53d7662e4cd2f518f36167fe7c014dbcf37a941a4a8324f7db"}, {"name":"cssbundling-rails","version":"1.4.1","platform":"ruby","checksum":"4b21273d627b21890da9155c88c67efc9274373d8b0add09149c262cf56c7ce1"},
{"name":"cvss-suite","version":"3.0.1","platform":"ruby","checksum":"b5ca9e9e94032a42fd0dc28c1e305378b62c949e35ed7111fc4a1d76f68ad3f9"}, {"name":"cvss-suite","version":"3.0.1","platform":"ruby","checksum":"b5ca9e9e94032a42fd0dc28c1e305378b62c949e35ed7111fc4a1d76f68ad3f9"},
{"name":"danger","version":"9.4.2","platform":"ruby","checksum":"43e552c6731030235a30fdeafe703d2e2ab9c30917154489cb0ecd9ad3259d80"}, {"name":"danger","version":"9.4.2","platform":"ruby","checksum":"43e552c6731030235a30fdeafe703d2e2ab9c30917154489cb0ecd9ad3259d80"},
{"name":"danger-gitlab","version":"8.0.0","platform":"ruby","checksum":"497dd7d0f6513913de651019223d8058cf494df10acbd17de92b175dfa04a3a8"}, {"name":"danger-gitlab","version":"8.0.0","platform":"ruby","checksum":"497dd7d0f6513913de651019223d8058cf494df10acbd17de92b175dfa04a3a8"},
@ -148,6 +148,7 @@
{"name":"elasticsearch-transport","version":"7.17.11","platform":"ruby","checksum":"d18057d5295e4c39fe80084ede9e00e9c0e0d74580348985f8677b2fb7f70f03"}, {"name":"elasticsearch-transport","version":"7.17.11","platform":"ruby","checksum":"d18057d5295e4c39fe80084ede9e00e9c0e0d74580348985f8677b2fb7f70f03"},
{"name":"email_reply_trimmer","version":"0.1.6","platform":"ruby","checksum":"9fede222ce660993e4e2e3dad282535ceb7914e246eb8302c19aa9e021f7326e"}, {"name":"email_reply_trimmer","version":"0.1.6","platform":"ruby","checksum":"9fede222ce660993e4e2e3dad282535ceb7914e246eb8302c19aa9e021f7326e"},
{"name":"email_spec","version":"2.2.0","platform":"ruby","checksum":"60b7980580a835e7f676db60667f17a2d60e8e0e39c26d81cfc231805c544d79"}, {"name":"email_spec","version":"2.2.0","platform":"ruby","checksum":"60b7980580a835e7f676db60667f17a2d60e8e0e39c26d81cfc231805c544d79"},
{"name":"email_validator","version":"2.2.4","platform":"ruby","checksum":"5ab238095bec7aef9389f230e9e0c64c5081cdf91f19d6c5cecee0a93af20604"},
{"name":"encryptor","version":"3.0.0","platform":"ruby","checksum":"abf23f94ab4d864b8cea85b43f3432044a60001982cda7c33c1cd90da8db1969"}, {"name":"encryptor","version":"3.0.0","platform":"ruby","checksum":"abf23f94ab4d864b8cea85b43f3432044a60001982cda7c33c1cd90da8db1969"},
{"name":"erubi","version":"1.12.0","platform":"ruby","checksum":"27bedb74dfb1e04ff60674975e182d8ca787f2224f2e8143268c7696f42e4723"}, {"name":"erubi","version":"1.12.0","platform":"ruby","checksum":"27bedb74dfb1e04ff60674975e182d8ca787f2224f2e8143268c7696f42e4723"},
{"name":"escape_utils","version":"1.3.0","platform":"ruby","checksum":"dffb7010922880ace6ceed642156c64e2a64620f27e0849f43bc4f68fd3c2c09"}, {"name":"escape_utils","version":"1.3.0","platform":"ruby","checksum":"dffb7010922880ace6ceed642156c64e2a64620f27e0849f43bc4f68fd3c2c09"},
@ -335,7 +336,7 @@
{"name":"js_regex","version":"3.8.0","platform":"ruby","checksum":"7934bcdd5a0e6d5af4a520288fd4684a02a472ae55831d9178ccaf82356344b5"}, {"name":"js_regex","version":"3.8.0","platform":"ruby","checksum":"7934bcdd5a0e6d5af4a520288fd4684a02a472ae55831d9178ccaf82356344b5"},
{"name":"json","version":"2.7.2","platform":"java","checksum":"138e3038b5361b3d06ee2e8aa2be00bed0d0de4ef5f1553fc5935e5b93aca7ee"}, {"name":"json","version":"2.7.2","platform":"java","checksum":"138e3038b5361b3d06ee2e8aa2be00bed0d0de4ef5f1553fc5935e5b93aca7ee"},
{"name":"json","version":"2.7.2","platform":"ruby","checksum":"1898b5cbc81cd36c0fd4d0b7ad2682c39fb07c5ff682fc6265f678f550d4982c"}, {"name":"json","version":"2.7.2","platform":"ruby","checksum":"1898b5cbc81cd36c0fd4d0b7ad2682c39fb07c5ff682fc6265f678f550d4982c"},
{"name":"json-jwt","version":"1.15.3","platform":"ruby","checksum":"66db4f14e538a774c15502a5b5b26b1f3e7585481bbb96df490aa74b5c2d6110"}, {"name":"json-jwt","version":"1.16.6","platform":"ruby","checksum":"ab451f9cd8743cecc4137f4170806046c1d8a6d4ee6e8570e0b5c958409b266c"},
{"name":"json_schemer","version":"2.3.0","platform":"ruby","checksum":"9f1fa173b859ca520f15e9e8d08b0892ffca80b78dd8221feb3e360ff4cdeb35"}, {"name":"json_schemer","version":"2.3.0","platform":"ruby","checksum":"9f1fa173b859ca520f15e9e8d08b0892ffca80b78dd8221feb3e360ff4cdeb35"},
{"name":"jsonb_accessor","version":"1.3.10","platform":"java","checksum":"6630ac69dac46457b03e1352178ed3e2d7ba2d8edb99f2e9b64a0e60cda9ed26"}, {"name":"jsonb_accessor","version":"1.3.10","platform":"java","checksum":"6630ac69dac46457b03e1352178ed3e2d7ba2d8edb99f2e9b64a0e60cda9ed26"},
{"name":"jsonb_accessor","version":"1.3.10","platform":"ruby","checksum":"670f80a257ae39e3be9233c6a8ef3b03517e06687affe510dfe61237454c58e0"}, {"name":"jsonb_accessor","version":"1.3.10","platform":"ruby","checksum":"670f80a257ae39e3be9233c6a8ef3b03517e06687affe510dfe61237454c58e0"},
@ -345,7 +346,7 @@
{"name":"kaminari-actionview","version":"1.2.2","platform":"ruby","checksum":"1330f6fc8b59a4a4ef6a549ff8a224797289ebf7a3a503e8c1652535287cc909"}, {"name":"kaminari-actionview","version":"1.2.2","platform":"ruby","checksum":"1330f6fc8b59a4a4ef6a549ff8a224797289ebf7a3a503e8c1652535287cc909"},
{"name":"kaminari-activerecord","version":"1.2.2","platform":"ruby","checksum":"0dd3a67bab356a356f36b3b7236bcb81cef313095365befe8e98057dd2472430"}, {"name":"kaminari-activerecord","version":"1.2.2","platform":"ruby","checksum":"0dd3a67bab356a356f36b3b7236bcb81cef313095365befe8e98057dd2472430"},
{"name":"kaminari-core","version":"1.2.2","platform":"ruby","checksum":"3bd26fec7370645af40ca73b9426a448d09b8a8ba7afa9ba3c3e0d39cdbb83ff"}, {"name":"kaminari-core","version":"1.2.2","platform":"ruby","checksum":"3bd26fec7370645af40ca73b9426a448d09b8a8ba7afa9ba3c3e0d39cdbb83ff"},
{"name":"kas-grpc","version":"0.5.0","platform":"ruby","checksum":"6c796f5afb1f1f37ae7a9d958d9f4b0ba46249e0dd4ca6ee268d4210b85dce35"}, {"name":"kas-grpc","version":"0.6.0","platform":"ruby","checksum":"43f7364cf45d50d5696ca4e1689bb648f22e5cec70fcf8ffe58330c04455af79"},
{"name":"knapsack","version":"4.0.0","platform":"ruby","checksum":"a9422688751989d09a40b4bf7f959a71a3bfe7bc49d3cd610c2fcfb6e45482b8"}, {"name":"knapsack","version":"4.0.0","platform":"ruby","checksum":"a9422688751989d09a40b4bf7f959a71a3bfe7bc49d3cd610c2fcfb6e45482b8"},
{"name":"kramdown","version":"2.3.2","platform":"ruby","checksum":"cb4530c2e9d16481591df2c9336723683c354e5416a5dd3e447fa48215a6a71c"}, {"name":"kramdown","version":"2.3.2","platform":"ruby","checksum":"cb4530c2e9d16481591df2c9336723683c354e5416a5dd3e447fa48215a6a71c"},
{"name":"kramdown-parser-gfm","version":"1.1.0","platform":"ruby","checksum":"fb39745516427d2988543bf01fc4cf0ab1149476382393e0e9c48592f6581729"}, {"name":"kramdown-parser-gfm","version":"1.1.0","platform":"ruby","checksum":"fb39745516427d2988543bf01fc4cf0ab1149476382393e0e9c48592f6581729"},
@ -444,9 +445,9 @@
{"name":"omniauth-oauth2-generic","version":"0.2.8","platform":"ruby","checksum":"ce6e8539019d5ebf2f48867072b9f248f148bb4cbe7166dee655865abfae7613"}, {"name":"omniauth-oauth2-generic","version":"0.2.8","platform":"ruby","checksum":"ce6e8539019d5ebf2f48867072b9f248f148bb4cbe7166dee655865abfae7613"},
{"name":"omniauth-saml","version":"2.1.0","platform":"ruby","checksum":"969cb7ba271891d09dfa57b206fc274f43203c52727492517decda93decc6906"}, {"name":"omniauth-saml","version":"2.1.0","platform":"ruby","checksum":"969cb7ba271891d09dfa57b206fc274f43203c52727492517decda93decc6906"},
{"name":"omniauth-shibboleth-redux","version":"2.0.0","platform":"ruby","checksum":"e9b353fd103405fcc8549e8510b9cad857acf0b286d764fac5dba8a93ab8ffe1"}, {"name":"omniauth-shibboleth-redux","version":"2.0.0","platform":"ruby","checksum":"e9b353fd103405fcc8549e8510b9cad857acf0b286d764fac5dba8a93ab8ffe1"},
{"name":"omniauth_openid_connect","version":"0.6.1","platform":"ruby","checksum":"5f1318f5b19b05e339ff494def060b57a503b1e3ea83c3a0ced6cc014407d423"}, {"name":"omniauth_openid_connect","version":"0.8.0","platform":"ruby","checksum":"1f2f3890386e2a742221cee0d2e903b78d874e6fab9ea3bfa31c1462f4793d25"},
{"name":"open4","version":"1.3.4","platform":"ruby","checksum":"a1df037310624ecc1ea1d81264b11c83e96d0c3c1c6043108d37d396dcd0f4b1"}, {"name":"open4","version":"1.3.4","platform":"ruby","checksum":"a1df037310624ecc1ea1d81264b11c83e96d0c3c1c6043108d37d396dcd0f4b1"},
{"name":"openid_connect","version":"1.3.0","platform":"ruby","checksum":"a796855096850cc01140e37ea6ae9fd14f2be818b9b5bc698418063dfe228770"}, {"name":"openid_connect","version":"2.3.0","platform":"ruby","checksum":"0dbb9cefeb11e0a65e706349266355bbbb060382ae138fc9e199ab1aa622744c"},
{"name":"openssl","version":"3.1.0","platform":"ruby","checksum":"e3a01279e918a7a5cf741db69b124864878b1a9783b1f2d34854bc1d444ac430"}, {"name":"openssl","version":"3.1.0","platform":"ruby","checksum":"e3a01279e918a7a5cf741db69b124864878b1a9783b1f2d34854bc1d444ac430"},
{"name":"openssl-signature_algorithm","version":"1.3.0","platform":"ruby","checksum":"a3b40b5e8276162d4a6e50c7c97cdaf1446f9b2c3946a6fa2c14628e0c957e80"}, {"name":"openssl-signature_algorithm","version":"1.3.0","platform":"ruby","checksum":"a3b40b5e8276162d4a6e50c7c97cdaf1446f9b2c3946a6fa2c14628e0c957e80"},
{"name":"opentelemetry-api","version":"1.2.5","platform":"ruby","checksum":"ab3d9a0566cd2ee068ade40e840bc973383ab8568e693c0c5712f0c789122cc9"}, {"name":"opentelemetry-api","version":"1.2.5","platform":"ruby","checksum":"ab3d9a0566cd2ee068ade40e840bc973383ab8568e693c0c5712f0c789122cc9"},
@ -526,7 +527,7 @@
{"name":"rack-accept","version":"0.4.5","platform":"ruby","checksum":"66247b5449db64ebb93ae2ec4af4764b87d1ae8a7463c7c68893ac13fa8d4da2"}, {"name":"rack-accept","version":"0.4.5","platform":"ruby","checksum":"66247b5449db64ebb93ae2ec4af4764b87d1ae8a7463c7c68893ac13fa8d4da2"},
{"name":"rack-attack","version":"6.7.0","platform":"ruby","checksum":"3ca47e8f66cd33b2c96af53ea4754525cd928ed3fa8da10ee6dad0277791d77c"}, {"name":"rack-attack","version":"6.7.0","platform":"ruby","checksum":"3ca47e8f66cd33b2c96af53ea4754525cd928ed3fa8da10ee6dad0277791d77c"},
{"name":"rack-cors","version":"2.0.2","platform":"ruby","checksum":"415d4e1599891760c5dc9ef0349c7fecdf94f7c6a03e75b2e7c2b54b82adda1b"}, {"name":"rack-cors","version":"2.0.2","platform":"ruby","checksum":"415d4e1599891760c5dc9ef0349c7fecdf94f7c6a03e75b2e7c2b54b82adda1b"},
{"name":"rack-oauth2","version":"1.21.3","platform":"ruby","checksum":"4e72a79dd6a866692e84422a552b27c38a5a1918ded06661e04910f2bbe676ba"}, {"name":"rack-oauth2","version":"2.2.1","platform":"ruby","checksum":"c73aa87c508043e2258f02b4fb110cacba9b37d2ccf884e22487d014a120d1a5"},
{"name":"rack-protection","version":"2.2.2","platform":"ruby","checksum":"fd41414dbabbec274af0bdb1f72a48504449de4d979782c9af38cbb5dfff3299"}, {"name":"rack-protection","version":"2.2.2","platform":"ruby","checksum":"fd41414dbabbec274af0bdb1f72a48504449de4d979782c9af38cbb5dfff3299"},
{"name":"rack-proxy","version":"0.7.7","platform":"ruby","checksum":"446a4b57001022145d5c3ba73b775f66a2260eaf7420c6907483141900395c8a"}, {"name":"rack-proxy","version":"0.7.7","platform":"ruby","checksum":"446a4b57001022145d5c3ba73b775f66a2260eaf7420c6907483141900395c8a"},
{"name":"rack-session","version":"1.0.2","platform":"ruby","checksum":"a02115e5420b4de036839b9811e3f7967d73446a554b42aa45106af335851d76"}, {"name":"rack-session","version":"1.0.2","platform":"ruby","checksum":"a02115e5420b4de036839b9811e3f7967d73446a554b42aa45106af335851d76"},
@ -699,7 +700,7 @@
{"name":"strings-ansi","version":"0.2.0","platform":"ruby","checksum":"90262d760ea4a94cc2ae8d58205277a343409c288cbe7c29416b1826bd511c88"}, {"name":"strings-ansi","version":"0.2.0","platform":"ruby","checksum":"90262d760ea4a94cc2ae8d58205277a343409c288cbe7c29416b1826bd511c88"},
{"name":"strscan","version":"3.1.0","platform":"java","checksum":"8645aa76e017e21764c6df572d2d79fcc1672284014f5bdbd806278cdbcd11b0"}, {"name":"strscan","version":"3.1.0","platform":"java","checksum":"8645aa76e017e21764c6df572d2d79fcc1672284014f5bdbd806278cdbcd11b0"},
{"name":"strscan","version":"3.1.0","platform":"ruby","checksum":"01b8a81d214fbf7b5308c6fb51b5972bbfc4a6aa1f166fd3618ba97e0fcd5555"}, {"name":"strscan","version":"3.1.0","platform":"ruby","checksum":"01b8a81d214fbf7b5308c6fb51b5972bbfc4a6aa1f166fd3618ba97e0fcd5555"},
{"name":"swd","version":"1.3.0","platform":"ruby","checksum":"bc382a19e1d36a95529b25152976db61b80376c3d486b21c8dd60ac2b5c06389"}, {"name":"swd","version":"2.0.3","platform":"ruby","checksum":"4cdbe2a4246c19f093fce22e967ec3ebdd4657d37673672e621bf0c7eb770655"},
{"name":"sync","version":"0.5.0","platform":"ruby","checksum":"668356cc07c59ac7ed9ecf34fec3929831f179c07adb1f3e1c3b7a1609a638fd"}, {"name":"sync","version":"0.5.0","platform":"ruby","checksum":"668356cc07c59ac7ed9ecf34fec3929831f179c07adb1f3e1c3b7a1609a638fd"},
{"name":"sys-filesystem","version":"1.4.3","platform":"ruby","checksum":"390919de89822ad6d3ba3daf694d720be9d83ed95cdf7adf54d4573c98b17421"}, {"name":"sys-filesystem","version":"1.4.3","platform":"ruby","checksum":"390919de89822ad6d3ba3daf694d720be9d83ed95cdf7adf54d4573c98b17421"},
{"name":"sysexits","version":"1.2.0","platform":"ruby","checksum":"598241c4ae57baa403c125182dfdcc0d1ac4c0fb606dd47fbed57e4aaf795662"}, {"name":"sysexits","version":"1.2.0","platform":"ruby","checksum":"598241c4ae57baa403c125182dfdcc0d1ac4c0fb606dd47fbed57e4aaf795662"},
@ -738,7 +739,7 @@
{"name":"typhoeus","version":"1.4.0","platform":"ruby","checksum":"fff9880d5dc35950e7706cf132fd297f377c049101794be1cf01c95567f642d4"}, {"name":"typhoeus","version":"1.4.0","platform":"ruby","checksum":"fff9880d5dc35950e7706cf132fd297f377c049101794be1cf01c95567f642d4"},
{"name":"tzinfo","version":"2.0.6","platform":"ruby","checksum":"8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b"}, {"name":"tzinfo","version":"2.0.6","platform":"ruby","checksum":"8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b"},
{"name":"uber","version":"0.1.0","platform":"ruby","checksum":"5beeb407ff807b5db994f82fa9ee07cfceaa561dad8af20be880bc67eba935dc"}, {"name":"uber","version":"0.1.0","platform":"ruby","checksum":"5beeb407ff807b5db994f82fa9ee07cfceaa561dad8af20be880bc67eba935dc"},
{"name":"undercover","version":"0.4.6","platform":"ruby","checksum":"7255959205be7ba492731d4376d89d7cceaed1e675a14ae55c90f71a1621e6ae"}, {"name":"undercover","version":"0.5.0","platform":"ruby","checksum":"ef99a8478be5466fb13fcd199f659ae308b81f71145a5a4e57428ff67d109fae"},
{"name":"unf","version":"0.1.4","platform":"java","checksum":"49a5972ec0b3d091d3b0b2e00113f2f342b9b212f0db855eb30a629637f6d302"}, {"name":"unf","version":"0.1.4","platform":"java","checksum":"49a5972ec0b3d091d3b0b2e00113f2f342b9b212f0db855eb30a629637f6d302"},
{"name":"unf","version":"0.1.4","platform":"ruby","checksum":"4999517a531f2a955750f8831941891f6158498ec9b6cb1c81ce89388e63022e"}, {"name":"unf","version":"0.1.4","platform":"ruby","checksum":"4999517a531f2a955750f8831941891f6158498ec9b6cb1c81ce89388e63022e"},
{"name":"unf_ext","version":"0.0.8.2","platform":"ruby","checksum":"90b9623ee359cc4878461c5d2eab7d3d3ce5801a680a9e7ac83b8040c5b742fa"}, {"name":"unf_ext","version":"0.0.8.2","platform":"ruby","checksum":"90b9623ee359cc4878461c5d2eab7d3d3ce5801a680a9e7ac83b8040c5b742fa"},
@ -752,7 +753,6 @@
{"name":"unparser","version":"0.6.7","platform":"ruby","checksum":"ae42e73edfa273766e66c166368fb75ca5972cd8ec50c536253e0f6299a9dec8"}, {"name":"unparser","version":"0.6.7","platform":"ruby","checksum":"ae42e73edfa273766e66c166368fb75ca5972cd8ec50c536253e0f6299a9dec8"},
{"name":"uri","version":"0.13.0","platform":"ruby","checksum":"26553c2a9399762e1e8bebd4444b4361c4b21298cf1c864b22eeabc9c4998f24"}, {"name":"uri","version":"0.13.0","platform":"ruby","checksum":"26553c2a9399762e1e8bebd4444b4361c4b21298cf1c864b22eeabc9c4998f24"},
{"name":"valid_email","version":"0.1.3","platform":"ruby","checksum":"b81452b51b64c4beb67913f68db52c20ecb4d73d45512f5b282ab4a3f4416570"}, {"name":"valid_email","version":"0.1.3","platform":"ruby","checksum":"b81452b51b64c4beb67913f68db52c20ecb4d73d45512f5b282ab4a3f4416570"},
{"name":"validate_email","version":"0.1.6","platform":"ruby","checksum":"9dfe9016d527b17a8d3a6e95e4dc50a125400eef899d13d4cc2a254393f82ee4"},
{"name":"validate_url","version":"1.0.15","platform":"ruby","checksum":"72fe164c0713d63a9970bd6700bea948babbfbdcec392f2342b6704042f57451"}, {"name":"validate_url","version":"1.0.15","platform":"ruby","checksum":"72fe164c0713d63a9970bd6700bea948babbfbdcec392f2342b6704042f57451"},
{"name":"validates_hostname","version":"1.0.13","platform":"ruby","checksum":"eac40178cc0b4f727df9cc6a5cb5bc2550718ad8d9bb3728df9aba6354bdda19"}, {"name":"validates_hostname","version":"1.0.13","platform":"ruby","checksum":"eac40178cc0b4f727df9cc6a5cb5bc2550718ad8d9bb3728df9aba6354bdda19"},
{"name":"version_gem","version":"1.1.0","platform":"ruby","checksum":"6b009518020db57f51ec7b410213fae2bf692baea9f1b51770db97fbc93d9a80"}, {"name":"version_gem","version":"1.1.0","platform":"ruby","checksum":"6b009518020db57f51ec7b410213fae2bf692baea9f1b51770db97fbc93d9a80"},
@ -765,7 +765,7 @@
{"name":"warden","version":"1.2.9","platform":"ruby","checksum":"46684f885d35a69dbb883deabf85a222c8e427a957804719e143005df7a1efd0"}, {"name":"warden","version":"1.2.9","platform":"ruby","checksum":"46684f885d35a69dbb883deabf85a222c8e427a957804719e143005df7a1efd0"},
{"name":"warning","version":"1.3.0","platform":"ruby","checksum":"23695a5d8e50bd5c46068931b529bee0b28e4982cbcefbe77d867800dde8069e"}, {"name":"warning","version":"1.3.0","platform":"ruby","checksum":"23695a5d8e50bd5c46068931b529bee0b28e4982cbcefbe77d867800dde8069e"},
{"name":"webauthn","version":"3.0.0","platform":"ruby","checksum":"3f77d422c2a8a4b31e56cf42f83414bd066e0506e9896936e1730262dc4a20e6"}, {"name":"webauthn","version":"3.0.0","platform":"ruby","checksum":"3f77d422c2a8a4b31e56cf42f83414bd066e0506e9896936e1730262dc4a20e6"},
{"name":"webfinger","version":"1.2.0","platform":"ruby","checksum":"7814ef1c85da47514f65c6e5ca14205fa9ce41ea2a70785e0c872842162852a2"}, {"name":"webfinger","version":"2.1.3","platform":"ruby","checksum":"567a52bde77fb38ca6b67e55db755f988766ec4651c1d24916a65aa70540695c"},
{"name":"webmock","version":"3.23.1","platform":"ruby","checksum":"0fa738c0767d1c4ec8cc57f6b21998f0c238c8a5b32450df1c847f2767140d95"}, {"name":"webmock","version":"3.23.1","platform":"ruby","checksum":"0fa738c0767d1c4ec8cc57f6b21998f0c238c8a5b32450df1c847f2767140d95"},
{"name":"webrick","version":"1.8.1","platform":"ruby","checksum":"19411ec6912911fd3df13559110127ea2badd0c035f7762873f58afc803e158f"}, {"name":"webrick","version":"1.8.1","platform":"ruby","checksum":"19411ec6912911fd3df13559110127ea2badd0c035f7762873f58afc803e158f"},
{"name":"websocket","version":"1.2.10","platform":"ruby","checksum":"2cc1a4a79b6e63637b326b4273e46adcddf7871caa5dc5711f2ca4061a629fa8"}, {"name":"websocket","version":"1.2.10","platform":"ruby","checksum":"2cc1a4a79b6e63637b326b4273e46adcddf7871caa5dc5711f2ca4061a629fa8"},

View File

@ -2,7 +2,7 @@ PATH
remote: gems/activerecord-gitlab remote: gems/activerecord-gitlab
specs: specs:
activerecord-gitlab (0.2.0) activerecord-gitlab (0.2.0)
activerecord (< 7.2) activerecord (>= 7)
PATH PATH
remote: gems/click_house-client remote: gems/click_house-client
@ -321,26 +321,26 @@ GEM
io-event (~> 1.6, >= 1.6.5) io-event (~> 1.6, >= 1.6.5)
atlassian-jwt (0.2.1) atlassian-jwt (0.2.1)
jwt (~> 2.1) jwt (~> 2.1)
attr_required (1.0.1) attr_required (1.0.2)
awesome_print (1.9.2) awesome_print (1.9.2)
awrence (1.2.1) awrence (1.2.1)
aws-eventstream (1.3.0) aws-eventstream (1.3.0)
aws-partitions (1.877.0) aws-partitions (1.960.0)
aws-sdk-cloudformation (1.41.0) aws-sdk-cloudformation (1.41.0)
aws-sdk-core (~> 3, >= 3.99.0) aws-sdk-core (~> 3, >= 3.99.0)
aws-sigv4 (~> 1.1) aws-sigv4 (~> 1.1)
aws-sdk-core (3.200.0) aws-sdk-core (3.201.3)
aws-eventstream (~> 1, >= 1.3.0) aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0) aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.8) aws-sigv4 (~> 1.8)
jmespath (~> 1, >= 1.6.1) jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.76.0) aws-sdk-kms (1.88.0)
aws-sdk-core (~> 3, >= 3.188.0) aws-sdk-core (~> 3, >= 3.201.0)
aws-sigv4 (~> 1.1) aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.155.0) aws-sdk-s3 (1.156.0)
aws-sdk-core (~> 3, >= 3.199.0) aws-sdk-core (~> 3, >= 3.201.0)
aws-sdk-kms (~> 1) aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.8) aws-sigv4 (~> 1.5)
aws-sigv4 (1.8.0) aws-sigv4 (1.8.0)
aws-eventstream (~> 1, >= 1.0.2) aws-eventstream (~> 1, >= 1.0.2)
axe-core-api (4.9.1) axe-core-api (4.9.1)
@ -451,7 +451,7 @@ GEM
git git
css_parser (1.14.0) css_parser (1.14.0)
addressable addressable
cssbundling-rails (1.4.0) cssbundling-rails (1.4.1)
railties (>= 6.0.0) railties (>= 6.0.0)
cvss-suite (3.0.1) cvss-suite (3.0.1)
danger (9.4.2) danger (9.4.2)
@ -568,6 +568,8 @@ GEM
htmlentities (~> 4.3.3) htmlentities (~> 4.3.3)
launchy (~> 2.1) launchy (~> 2.1)
mail (~> 2.7) mail (~> 2.7)
email_validator (2.2.4)
activemodel
encryptor (3.0.0) encryptor (3.0.0)
erubi (1.12.0) erubi (1.12.0)
escape_utils (1.3.0) escape_utils (1.3.0)
@ -1005,11 +1007,13 @@ GEM
regexp_parser (~> 2.5) regexp_parser (~> 2.5)
regexp_property_values (~> 1.0) regexp_property_values (~> 1.0)
json (2.7.2) json (2.7.2)
json-jwt (1.15.3) json-jwt (1.16.6)
activesupport (>= 4.2) activesupport (>= 4.2)
aes_key_wrap aes_key_wrap
base64
bindata bindata
httpclient faraday (~> 2.0)
faraday-follow_redirects
json_schemer (2.3.0) json_schemer (2.3.0)
bigdecimal bigdecimal
hana (~> 1.3) hana (~> 1.3)
@ -1034,7 +1038,7 @@ GEM
activerecord activerecord
kaminari-core (= 1.2.2) kaminari-core (= 1.2.2)
kaminari-core (1.2.2) kaminari-core (1.2.2)
kas-grpc (0.5.0) kas-grpc (0.6.0)
grpc (~> 1.0) grpc (~> 1.0)
knapsack (4.0.0) knapsack (4.0.0)
rake rake
@ -1232,20 +1236,23 @@ GEM
ruby-saml (~> 1.12) ruby-saml (~> 1.12)
omniauth-shibboleth-redux (2.0.0) omniauth-shibboleth-redux (2.0.0)
omniauth (>= 2.0.0) omniauth (>= 2.0.0)
omniauth_openid_connect (0.6.1) omniauth_openid_connect (0.8.0)
omniauth (>= 1.9, < 3) omniauth (>= 1.9, < 3)
openid_connect (~> 1.1) openid_connect (~> 2.2)
open4 (1.3.4) open4 (1.3.4)
openid_connect (1.3.0) openid_connect (2.3.0)
activemodel activemodel
attr_required (>= 1.0.0) attr_required (>= 1.0.0)
json-jwt (>= 1.5.0) email_validator
rack-oauth2 (>= 1.6.1) faraday (~> 2.0)
swd (>= 1.0.0) faraday-follow_redirects
json-jwt (>= 1.16)
mail
rack-oauth2 (~> 2.2)
swd (~> 2.0)
tzinfo tzinfo
validate_email
validate_url validate_url
webfinger (>= 1.0.1) webfinger (~> 2.0)
openssl (3.1.0) openssl (3.1.0)
openssl-signature_algorithm (1.3.0) openssl-signature_algorithm (1.3.0)
openssl (> 2.0) openssl (> 2.0)
@ -1439,10 +1446,11 @@ GEM
rack (>= 1.0, < 4) rack (>= 1.0, < 4)
rack-cors (2.0.2) rack-cors (2.0.2)
rack (>= 2.0.0) rack (>= 2.0.0)
rack-oauth2 (1.21.3) rack-oauth2 (2.2.1)
activesupport activesupport
attr_required attr_required
httpclient faraday (~> 2.0)
faraday-follow_redirects
json-jwt (>= 1.11.0) json-jwt (>= 1.11.0)
rack (>= 2.1.0) rack (>= 2.1.0)
rack-protection (2.2.2) rack-protection (2.2.2)
@ -1782,10 +1790,11 @@ GEM
unicode_utils (~> 1.4) unicode_utils (~> 1.4)
strings-ansi (0.2.0) strings-ansi (0.2.0)
strscan (3.1.0) strscan (3.1.0)
swd (1.3.0) swd (2.0.3)
activesupport (>= 3) activesupport (>= 3)
attr_required (>= 0.0.5) attr_required (>= 0.0.5)
httpclient (>= 2.4) faraday (~> 2.0)
faraday-follow_redirects
sync (0.5.0) sync (0.5.0)
sys-filesystem (1.4.3) sys-filesystem (1.4.3)
ffi (~> 1.1) ffi (~> 1.1)
@ -1857,10 +1866,11 @@ GEM
tzinfo (2.0.6) tzinfo (2.0.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
uber (0.1.0) uber (0.1.0)
undercover (0.4.6) undercover (0.5.0)
bigdecimal
imagen (>= 0.1.8) imagen (>= 0.1.8)
rainbow (>= 2.1, < 4.0) rainbow (>= 2.1, < 4.0)
rugged (>= 0.27, < 1.7) rugged (>= 0.27, < 1.8)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.8.2) unf_ext (0.0.8.2)
@ -1876,9 +1886,6 @@ GEM
valid_email (0.1.3) valid_email (0.1.3)
activemodel activemodel
mail (>= 2.6.1) mail (>= 2.6.1)
validate_email (0.1.6)
activemodel (>= 3.0)
mail (>= 2.2.5)
validate_url (1.0.15) validate_url (1.0.15)
activemodel (>= 3.0.0) activemodel (>= 3.0.0)
public_suffix public_suffix
@ -1915,9 +1922,10 @@ GEM
openssl (>= 2.2) openssl (>= 2.2)
safety_net_attestation (~> 0.4.0) safety_net_attestation (~> 0.4.0)
tpm-key_attestation (~> 0.12.0) tpm-key_attestation (~> 0.12.0)
webfinger (1.2.0) webfinger (2.1.3)
activesupport activesupport
httpclient (>= 2.4) faraday (~> 2.0)
faraday-follow_redirects
webmock (3.23.1) webmock (3.23.1)
addressable (>= 2.8.0) addressable (>= 2.8.0)
crack (>= 0.3.2) crack (>= 0.3.2)
@ -1966,8 +1974,8 @@ DEPENDENCIES
attr_encrypted (~> 3.2.4)! attr_encrypted (~> 3.2.4)!
awesome_print awesome_print
aws-sdk-cloudformation (~> 1) aws-sdk-cloudformation (~> 1)
aws-sdk-core (~> 3.200.0) aws-sdk-core (~> 3.201.0)
aws-sdk-s3 (~> 1.155.0) aws-sdk-s3 (~> 1.156.0)
axe-core-rspec (~> 4.9.0) axe-core-rspec (~> 4.9.0)
babosa (~> 2.0) babosa (~> 2.0)
base32 (~> 0.3.0) base32 (~> 0.3.0)
@ -1994,7 +2002,7 @@ DEPENDENCIES
coverband (= 6.1.2) coverband (= 6.1.2)
creole (~> 0.5.0) creole (~> 0.5.0)
crystalball (~> 0.7.0) crystalball (~> 0.7.0)
cssbundling-rails (= 1.4.0) cssbundling-rails (= 1.4.1)
csv_builder! csv_builder!
cvss-suite (~> 3.0.1) cvss-suite (~> 3.0.1)
database_cleaner-active_record (~> 2.2.0) database_cleaner-active_record (~> 2.2.0)
@ -2121,7 +2129,7 @@ DEPENDENCIES
jsonb_accessor (~> 1.3.10) jsonb_accessor (~> 1.3.10)
jwt (~> 2.5) jwt (~> 2.5)
kaminari (~> 1.2.2) kaminari (~> 1.2.2)
kas-grpc (~> 0.5.0) kas-grpc (~> 0.6.0)
knapsack (~> 4.0.0) knapsack (~> 4.0.0)
kramdown (~> 2.3.1) kramdown (~> 2.3.1)
kubeclient (~> 4.11.0) kubeclient (~> 4.11.0)
@ -2168,9 +2176,9 @@ DEPENDENCIES
omniauth-saml (~> 2.1.0) omniauth-saml (~> 2.1.0)
omniauth-shibboleth-redux (~> 2.0) omniauth-shibboleth-redux (~> 2.0)
omniauth_crowd (~> 2.4.0)! omniauth_crowd (~> 2.4.0)!
omniauth_openid_connect (~> 0.6.1) omniauth_openid_connect (~> 0.8.0)
openbao_client! openbao_client!
openid_connect (= 1.3.0) openid_connect (~> 2.3.0)
openssl (~> 3.0) openssl (~> 3.0)
opentelemetry-exporter-otlp opentelemetry-exporter-otlp
opentelemetry-instrumentation-action_pack opentelemetry-instrumentation-action_pack
@ -2214,7 +2222,7 @@ DEPENDENCIES
rack (~> 2.2.9) rack (~> 2.2.9)
rack-attack (~> 6.7.0) rack-attack (~> 6.7.0)
rack-cors (~> 2.0.1) rack-cors (~> 2.0.1)
rack-oauth2 (~> 1.21.3) rack-oauth2 (~> 2.2.1)
rack-proxy (~> 0.7.7) rack-proxy (~> 0.7.7)
rack-timeout (~> 0.7.0) rack-timeout (~> 0.7.0)
rails (~> 7.1.3.4) rails (~> 7.1.3.4)
@ -2292,7 +2300,7 @@ DEPENDENCIES
truncato (~> 0.7.12) truncato (~> 0.7.12)
tty-prompt (~> 0.23) tty-prompt (~> 0.23)
typhoeus (~> 1.4.0) typhoeus (~> 1.4.0)
undercover (~> 0.4.4) undercover (~> 0.5.0)
unleash (~> 3.2.2) unleash (~> 3.2.2)
valid_email (~> 0.1) valid_email (~> 0.1)
validates_hostname (~> 1.0.13) validates_hostname (~> 1.0.13)

View File

@ -1,12 +1,11 @@
<script> <script>
import { GlLink } from '@gitlab/ui'; import { GlLink, GlExperimentBadge } from '@gitlab/ui';
import ExperimentBadge from '~/vue_shared/components/badges/experiment_badge.vue';
export default { export default {
name: 'LogViewerFeedbackPopover', name: 'LogViewerTopBar',
components: { components: {
GlLink, GlLink,
ExperimentBadge, GlExperimentBadge,
}, },
}; };
</script> </script>
@ -14,10 +13,10 @@ export default {
<div <div
class="job-log-viewer-top-bar gl-display-flex gl-align-items-center gl-justify-content-space-between" class="job-log-viewer-top-bar gl-display-flex gl-align-items-center gl-justify-content-space-between"
> >
<div>{{ s__('Job|Full log viewer') }} <experiment-badge class="gl-inline" /></div> <div>{{ s__('Job|Full log viewer') }}<gl-experiment-badge /></div>
<div> <div>
<gl-link href="https://gitlab.com/gitlab-org/gitlab/-/issues/454817" target="_blank">{{ <gl-link href="https://gitlab.com/gitlab-org/gitlab/-/issues/454817" target="_blank">{{
s__('Job|Feedback issue') s__('Job|Give feedback')
}}</gl-link> }}</gl-link>
</div> </div>
</div> </div>

View File

@ -75,3 +75,7 @@ export const ERROR_LOADING_FULL_DIFF = s__(
export const ERROR_DISMISSING_SUGESTION_POPOVER = s__( export const ERROR_DISMISSING_SUGESTION_POPOVER = s__(
'MergeRequest|Error dismissing suggestion popover. Please try again.', 'MergeRequest|Error dismissing suggestion popover. Please try again.',
); );
export const ENCODED_FILE_PATHS_TITLE = __('Some changes are not shown.');
export const ENCODED_FILE_PATHS_MESSAGE = __(
'Some files cannot be displayed due to their file path encoding.',
);

View File

@ -61,6 +61,8 @@ import {
SOMETHING_WENT_WRONG, SOMETHING_WENT_WRONG,
ERROR_LOADING_FULL_DIFF, ERROR_LOADING_FULL_DIFF,
ERROR_DISMISSING_SUGESTION_POPOVER, ERROR_DISMISSING_SUGESTION_POPOVER,
ENCODED_FILE_PATHS_TITLE,
ENCODED_FILE_PATHS_MESSAGE,
} from '../i18n'; } from '../i18n';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import { markFileReview, setReviewsForMergeRequest } from '../utils/file_reviews'; import { markFileReview, setReviewsForMergeRequest } from '../utils/file_reviews';
@ -335,6 +337,14 @@ export const fetchDiffFilesMeta = ({ commit, state }) => {
const strippedData = { ...data }; const strippedData = { ...data };
delete strippedData.diff_files; delete strippedData.diff_files;
if (strippedData.has_encoded_file_paths) {
createAlert({
title: ENCODED_FILE_PATHS_TITLE,
message: ENCODED_FILE_PATHS_MESSAGE,
dismissible: false,
});
}
commit(types.SET_LOADING, false); commit(types.SET_LOADING, false);
commit(types.SET_MERGE_REQUEST_DIFFS, data.merge_request_diffs || []); commit(types.SET_MERGE_REQUEST_DIFFS, data.merge_request_diffs || []);
commit(types.SET_DIFF_METADATA, strippedData); commit(types.SET_DIFF_METADATA, strippedData);

View File

@ -1,82 +0,0 @@
<script>
import * as Sentry from '~/sentry/sentry_browser_wrapper';
import { logError } from '~/lib/logger';
import { buildClient } from '../client';
import ObservabilityLoader from './loader/index.vue';
import { CONTENT_STATE } from './loader/constants';
export default {
components: {
ObservabilityLoader,
},
props: {
apiConfig: {
type: Object,
required: true,
},
},
data() {
return {
observabilityClient: null,
authCompleted: false,
loaderContentState: null,
};
},
mounted() {
window.addEventListener('message', this.messageHandler);
// TODO: Improve local GDK dev experience with tracing https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2308
// Uncomment the lines below to to test this locally
// setTimeout(() => {
// this.messageHandler({
// data: { type: 'AUTH_COMPLETION', status: 'success' },
// origin: new URL(this.apiConfig.oauthUrl).origin,
// });
// }, 2000);
},
destroyed() {
window.removeEventListener('message', this.messageHandler);
},
methods: {
messageHandler(e) {
const isExpectedOrigin = e.origin === new URL(this.apiConfig.oauthUrl).origin;
if (!isExpectedOrigin) return;
const { data } = e;
if (data.type === 'AUTH_COMPLETION') {
if (this.authCompleted) return;
const { status, message, statusCode } = data;
if (status === 'success') {
this.observabilityClient = buildClient(this.apiConfig);
this.$emit('observability-client-ready', this.observabilityClient);
this.loaderContentState = CONTENT_STATE.LOADED;
} else if (status === 'error') {
const error = new Error(`GOB auth failed with error: ${message} - status: ${statusCode}`);
Sentry.captureException(error);
logError(error);
this.loaderContentState = CONTENT_STATE.ERROR;
}
this.authCompleted = true;
}
},
},
};
</script>
<template>
<div>
<iframe
v-if="!authCompleted"
sandbox="allow-same-origin allow-forms allow-scripts"
hidden
:src="apiConfig.oauthUrl"
data-testid="observability-oauth-iframe"
></iframe>
<observability-loader :content-state="loaderContentState">
<slot v-if="observabilityClient" :observability-client="observabilityClient"></slot>
</observability-loader>
</div>
</template>

View File

@ -1,95 +0,0 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import ObservabilityContainer from '~/observability/components/observability_container.vue';
import { s__ } from '~/locale';
import { createAlert } from '~/alert';
import ObservabilityNotEnabledEmptyState from './observability_not_enabled_empty_state.vue';
export default {
components: {
ObservabilityContainer,
ObservabilityNotEnabledEmptyState,
GlLoadingIcon,
},
props: {
apiConfig: {
type: Object,
required: true,
},
},
data() {
return {
loading: false,
/**
* observabilityEnabled: boolean | null.
* null identifies a state where we don't know if observability is enabled or not (e.g. when fetching the status from the API fails)
*/
observabilityEnabled: null,
observabilityClient: null,
};
},
computed: {
isObservabilityStatusKnown() {
return this.observabilityEnabled !== null;
},
isObservabilityDisabled() {
return this.observabilityEnabled === false;
},
isObservabilityEnabled() {
return this.observabilityEnabled;
},
},
methods: {
onObservabilityClientReady(client) {
this.observabilityClient = client;
this.checkEnabled();
},
async checkEnabled() {
this.loading = true;
try {
this.observabilityEnabled = await this.observabilityClient.isObservabilityEnabled();
} catch (e) {
createAlert({
message: s__('Observability|Error: Failed to load page. Try reloading the page.'),
});
} finally {
this.loading = false;
}
},
async onEnableObservability() {
this.loading = true;
try {
await this.observabilityClient.enableObservability();
this.observabilityEnabled = true;
} catch (e) {
createAlert({
message: s__(
'Observability|Error: Failed to enable GitLab Observability. Please retry later.',
),
});
} finally {
this.loading = false;
}
},
},
};
</script>
<template>
<observability-container
:api-config="apiConfig"
@observability-client-ready="onObservabilityClientReady"
>
<div v-if="loading" class="gl-py-5">
<gl-loading-icon size="lg" />
</div>
<template v-else-if="isObservabilityStatusKnown">
<observability-not-enabled-empty-state
v-if="isObservabilityDisabled"
@enable-observability="onEnableObservability"
/>
<slot v-if="isObservabilityEnabled" :observability-client="observabilityClient"></slot>
</template>
</observability-container>
</template>

View File

@ -3,9 +3,11 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import CommitsList from '~/commits'; import CommitsList from '~/commits';
import GpgBadges from '~/gpg_badges'; import GpgBadges from '~/gpg_badges';
import { mountCommits, initCommitsRefSwitcher } from '~/projects/commits'; import { mountCommits, initCommitsRefSwitcher } from '~/projects/commits';
import initAmbiguousRefModal from '~/ref/init_ambiguous_ref_modal';
new CommitsList(document.querySelector('.js-project-commits-show').dataset.commitsLimit); // eslint-disable-line no-new new CommitsList(document.querySelector('.js-project-commits-show').dataset.commitsLimit); // eslint-disable-line no-new
addShortcutsExtension(ShortcutsNavigation); addShortcutsExtension(ShortcutsNavigation);
GpgBadges.fetch(); GpgBadges.fetch();
mountCommits(document.getElementById('js-author-dropdown')); mountCommits(document.getElementById('js-author-dropdown'));
initCommitsRefSwitcher(); initCommitsRefSwitcher();
initAmbiguousRefModal();

View File

@ -1,24 +0,0 @@
import ExperimentBadge from './experiment_badge.vue';
export default {
component: ExperimentBadge,
title: 'vue_shared/experiment-badge',
};
const template = `
<div style="height:600px;" class="gl-flex gl-justify-center gl-items-center">
<experiment-badge />
</div>
`;
const Template = (args, { argTypes }) => ({
components: { ExperimentBadge },
data() {
return { value: args.value };
},
props: Object.keys(argTypes),
template,
});
export const Default = Template.bind({});
Default.args = {};

View File

@ -1,36 +0,0 @@
<script>
import { s__ } from '~/locale';
import HoverBadge from './hover_badge.vue';
export default {
name: 'ExperimentBadge',
components: { HoverBadge },
i18n: {
badgeLabel: s__('ExperimentBadge|Experiment'),
popoverTitle: s__("ExperimentBadge|What's an experiment?"),
descriptionParagraph: s__(
'ExperimentBadge|An experiment is not yet production-ready, but is released for initial testing and feedback during development.',
),
listIntroduction: s__('ExperimentBadge|Experiments:'),
listItemStability: s__('ExperimentBadge|Might be unstable or cause data loss.'),
listItemNoSupport: s__('ExperimentBadge|Are not supported and might not be documented.'),
listItemCanBeRemoved: s__('ExperimentBadge|Could be changed or removed at any time.'),
listItemTestAgreement: s__('ExperimentBadge|Are subject to the GitLab Testing Agreement.'),
},
};
</script>
<template>
<hover-badge :label="$options.i18n.badgeLabel" :title="$options.i18n.popoverTitle">
<p>{{ $options.i18n.descriptionParagraph }}</p>
<p class="gl-mb-0">{{ $options.i18n.listIntroduction }}</p>
<ul class="gl-pl-4">
<li>{{ $options.i18n.listItemStability }}</li>
<li>{{ $options.i18n.listItemNoSupport }}</li>
<li>{{ $options.i18n.listItemCanBeRemoved }}</li>
<li>{{ $options.i18n.listItemTestAgreement }}</li>
</ul>
</hover-badge>
</template>

View File

@ -1,9 +1,9 @@
.gl-card{ @card_options } .gl-card{ @card_options }
- if header? - if parsed_header?
.gl-card-header{ @header_options } .gl-card-header{ @header_options }
= header = parsed_header
.gl-card-body{ @body_options } .gl-card-body{ @body_options }
= body = parsed_body
- if footer? - if parsed_footer?
.gl-card-footer{ @footer_options } .gl-card-footer{ @footer_options }
= footer = parsed_footer

View File

@ -7,15 +7,41 @@ module Pajamas
# @param [Hash] header_options # @param [Hash] header_options
# @param [Hash] body_options # @param [Hash] body_options
# @param [Hash] footer_options # @param [Hash] footer_options
def initialize(card_options: {}, header_options: {}, body_options: {}, footer_options: {}) # @card [Hash] card structure as an object. This enables .with_collection functionality.
def initialize(card: {}, card_options: {}, header_options: {}, body_options: {}, footer_options: {})
@card_options = card_options @card_options = card_options
@header_options = header_options @header_options = header_options
@body_options = body_options @body_options = body_options
@footer_options = footer_options @footer_options = footer_options
@card = card
end end
renders_one :header renders_one :header
renders_one :body renders_one :body
renders_one :footer renders_one :footer
private
attr_reader :card
def parsed_header?
header? || card[:header].present?
end
def parsed_header
header || card[:header]
end
def parsed_body
body || card[:body]
end
def parsed_footer?
footer? || card[:footer].present?
end
def parsed_footer
footer || card[:footer]
end
end end
end end

View File

@ -4,9 +4,7 @@ module SynchronizeBroadcastMessageDismissals
extend ActiveSupport::Concern extend ActiveSupport::Concern
def synchronize_broadcast_message_dismissals def synchronize_broadcast_message_dismissals
message_ids = System::BroadcastMessage.current.map(&:id) Users::BroadcastMessageDismissalFinder.new(current_user).execute
Users::BroadcastMessageDismissalFinder.new(current_user, message_ids: message_ids).execute
.find_each do |dismissal| .find_each do |dismissal|
create_dismissal_cookie(dismissal) if cookies[dismissal.cookie_key].blank? create_dismissal_cookie(dismissal) if cookies[dismissal.cookie_key].blank?
end end
@ -15,13 +13,6 @@ module SynchronizeBroadcastMessageDismissals
private private
def create_dismissal_cookie(dismissal) def create_dismissal_cookie(dismissal)
Gitlab::AppLogger.info(
"Creating cookie for broadcast message dismissal: " \
"user_id=#{dismissal.user_id} " \
"broadcast_message_id=#{dismissal.broadcast_message_id} " \
"expires_at=#{dismissal.expires_at}"
)
cookies[dismissal.cookie_key] = { value: true, expires: dismissal.expires_at } cookies[dismissal.cookie_key] = { value: true, expires: dismissal.expires_at }
end end
end end

View File

@ -23,10 +23,8 @@ class Projects::BlobController < Projects::ApplicationController
# We need to assign the blob vars before `authorize_edit_tree!` so we can # We need to assign the blob vars before `authorize_edit_tree!` so we can
# validate access to a specific ref. # validate access to a specific ref.
before_action :assign_blob_vars before_action :assign_blob_vars, except: [:show]
before_action :assign_ref_vars, only: [:show]
# Since BlobController doesn't use assign_ref_vars, we have to call this explicitly
before_action :rectify_renamed_default_branch!, only: [:show]
before_action :authorize_edit_tree!, only: [:new, :create, :update, :destroy] before_action :authorize_edit_tree!, only: [:new, :create, :update, :destroy]

View File

@ -16,6 +16,7 @@ class Projects::CommitsController < Projects::ApplicationController
before_action :authorize_read_code! before_action :authorize_read_code!
before_action :validate_ref!, except: :commits_root before_action :validate_ref!, except: :commits_root
before_action :validate_path, if: -> { !request.format.atom? } before_action :validate_path, if: -> { !request.format.atom? }
before_action :set_is_ambiguous_ref, only: [:show]
before_action :set_commits, except: :commits_root before_action :set_commits, except: :commits_root
feature_category :source_code_management feature_category :source_code_management

View File

@ -195,7 +195,7 @@ module Repositories
def lfs_auth_header def lfs_auth_header
return unless user return unless user
Gitlab::LfsToken.new(user).basic_encoding Gitlab::LfsToken.new(user, project).basic_encoding
end end
def should_auto_link? def should_auto_link?

View File

@ -41,13 +41,9 @@ module Environments
def by_search(environments) def by_search(environments)
if params[:search].present? if params[:search].present?
if Feature.enabled?(:enable_environments_search_within_folder, project)
Environment.from_union( Environment.from_union(
environments.for_name_like(params[:search], limit: nil), environments.for_name_like(params[:search], limit: nil),
environments.for_name_like_within_folder(params[:search], limit: nil)) environments.for_name_like_within_folder(params[:search], limit: nil))
else
environments.for_name_like(params[:search], limit: nil)
end
else else
environments environments
end end

View File

@ -2,13 +2,12 @@
module Users module Users
class BroadcastMessageDismissalFinder class BroadcastMessageDismissalFinder
def initialize(user, message_ids:) def initialize(user)
@user = user @user = user
@message_ids = message_ids
end end
def execute def execute
Users::BroadcastMessageDismissal.valid_dismissals.for_user_and_broadcast_message(user, message_ids) Users::BroadcastMessageDismissal.valid_dismissals.for_user(user)
end end
private private

View File

@ -594,6 +594,10 @@ class Commit
repository.tag_names_contains(id, limit: limit, exclude_refs: excluded) || [] repository.tag_names_contains(id, limit: limit, exclude_refs: excluded) || []
end end
def has_encoded_file_paths?
raw_diffs.any?(&:encoded_file_path)
end
private private
def tipping_refs(ref_prefix, limit: 0) def tipping_refs(ref_prefix, limit: 0)

View File

@ -38,6 +38,10 @@ class ContextCommitsDiff
) )
end end
def has_encoded_file_paths?
merge_request.merge_request_context_commit_diff_files.where(encoded_file_path: true).any?
end
private private
def compare def compare

View File

@ -53,7 +53,7 @@ class DiffNote < Note
end end
creation_params = diff_file.diff.to_hash creation_params = diff_file.diff.to_hash
.except(:too_large, :generated) .except(:too_large, :generated, :encoded_file_path)
.merge(diff: diff_file.diff_hunk(diff_line)) .merge(diff: diff_file.diff_hunk(diff_line))
create_note_diff_file(creation_params) create_note_diff_file(creation_params)

View File

@ -646,6 +646,10 @@ class MergeRequestDiff < ApplicationRecord
FileUtils.rm_rf(external_diff_cache_dir) FileUtils.rm_rf(external_diff_cache_dir)
end end
def has_encoded_file_paths?
merge_request_diff_files.where(encoded_file_path: true).any?
end
private private
def convert_external_diffs_to_database def convert_external_diffs_to_database

View File

@ -32,7 +32,7 @@ class RefMatcher
def wildcard_match?(ref_name) def wildcard_match?(ref_name)
return false unless wildcard? return false unless wildcard?
wildcard_regex === ref_name wildcard_regex.match?(ref_name)
end end
def wildcard_regex def wildcard_regex
@ -40,7 +40,7 @@ class RefMatcher
name = @ref_name_or_pattern.gsub('*', 'STAR_DONT_ESCAPE') name = @ref_name_or_pattern.gsub('*', 'STAR_DONT_ESCAPE')
quoted_name = Regexp.quote(name) quoted_name = Regexp.quote(name)
regex_string = quoted_name.gsub('STAR_DONT_ESCAPE', '.*?') regex_string = quoted_name.gsub('STAR_DONT_ESCAPE', '.*?')
/\A#{regex_string}\z/ Gitlab::UntrustedRegexp.new("\\A#{regex_string}\\z")
end end
end end
end end

View File

@ -11,8 +11,8 @@ module Users
self.table_name = 'user_broadcast_message_dismissals' self.table_name = 'user_broadcast_message_dismissals'
scope :valid_dismissals, -> { where('expires_at > :now', now: Time.current) } scope :valid_dismissals, -> { where('expires_at > :now', now: Time.current) }
scope :for_user_and_broadcast_message, ->(user, message_ids) do scope :for_user, ->(user) do
where(user: user, broadcast_message_id: message_ids) where(user: user)
end end
BROADCAST_MESSAGE_DISMISSAL_COOKIE_KEY = 'hide_broadcast_message_' BROADCAST_MESSAGE_DISMISSAL_COOKIE_KEY = 'hide_broadcast_message_'

View File

@ -33,6 +33,17 @@ class DiffsMetadataEntity < DiffsEntity
expose :username expose :username
expose :user_full_name expose :user_full_name
expose :has_encoded_file_paths do |_, options|
diff =
if options[:only_context_commits]
options[:merge_request].context_commits_diff
else
options[:merge_request_diff].presence || options[:commit]
end
diff&.has_encoded_file_paths?
end
private private
def project_path def project_path

View File

@ -27,9 +27,7 @@ module Ci
runner = ::Ci::Runner.new(params) runner = ::Ci::Runner.new(params)
if Namespace.with_disabled_organization_validation { runner.save } return ServiceResponse.success(payload: { runner: runner }) if runner.save
return ServiceResponse.success(payload: { runner: runner })
end
ServiceResponse.error(message: runner.errors.full_messages, reason: :save_error) ServiceResponse.error(message: runner.errors.full_messages, reason: :save_error)
end end

View File

@ -1,13 +1,15 @@
- remove_form_id = 'js-remove-group-form' - remove_form_id = 'js-remove-group-form'
= render 'groups/settings/export', group: @group
= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card' }, header_options: { class: 'gl-new-card-header gl-flex-direction-column' }, body_options: { class: 'gl-new-card-body gl-px-5 gl-py-4' }) do |c| .gl-flex.gl-gap-5.gl-flex-col
= render 'groups/settings/export', group: @group
= render Pajamas::CardComponent.new(header_options: { class: 'gl-px-5 gl-py-4 gl-border-b-1 gl-border-b-solid gl-border-gray-100' }, body_options: { class: 'gl-px-5 gl-py-4' }) do |c|
- c.with_header do - c.with_header do
.gl-new-card-title-wrapper .gl-flex.gl-grow
%h4.gl-new-card-title.warning-title= s_('GroupSettings|Change group URL') %h4.gl-text-base.gl-leading-24.gl-m-0= s_('GroupSettings|Change group URL')
%p.gl-new-card-description %p.gl-text-subtle.gl-text-sm.gl-m-0
= s_("GroupSettings|Changing a group's URL can have unintended side effects.") = s_("GroupSettings|Changing a group's URL can have unintended side effects.")
= link_to _('Learn more.'), help_page_path('user/group/manage', anchor: 'change-a-groups-path'), target: '_blank', rel: 'noopener noreferrer' #{link_to _('Learn more'), help_page_path('user/group/manage', anchor: 'change-a-groups-path'), target: '_blank', rel: 'noopener noreferrer'}.
- c.with_body do - c.with_body do
= gitlab_ui_form_for @group, html: { multipart: true, class: 'gl-show-field-errors' }, authenticity_token: true do |f| = gitlab_ui_form_for @group, html: { multipart: true, class: 'gl-show-field-errors' }, authenticity_token: true do |f|
@ -28,7 +30,7 @@
"data-bind-in" => "#{'create_chat_team' if Gitlab.config.mattermost.enabled}" "data-bind-in" => "#{'create_chat_team' if Gitlab.config.mattermost.enabled}"
= f.submit s_('GroupSettings|Change group URL'), class: 'btn-danger', pajamas_button: true = f.submit s_('GroupSettings|Change group URL'), class: 'btn-danger', pajamas_button: true
= render 'groups/settings/transfer', group: @group = render 'groups/settings/transfer', group: @group
= render 'groups/settings/remove', group: @group, remove_form_id: remove_form_id = render 'groups/settings/remove', group: @group, remove_form_id: remove_form_id
= render_if_exists 'groups/settings/restore', group: @group = render_if_exists 'groups/settings/restore', group: @group
= render_if_exists 'groups/settings/immediately_remove', group: @group, remove_form_id: remove_form_id = render_if_exists 'groups/settings/immediately_remove', group: @group, remove_form_id: remove_form_id

View File

@ -1,10 +1,10 @@
- group = local_assigns.fetch(:group) - group = local_assigns.fetch(:group)
= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card' }, header_options: { class: 'gl-new-card-header gl-flex-direction-column' }, body_options: { class: 'gl-new-card-body gl-px-5 gl-py-4' }) do |c| = render Pajamas::CardComponent.new(header_options: { class: 'gl-px-5 gl-py-4 gl-border-b-1 gl-border-b-solid gl-border-gray-100' }, body_options: { class: 'gl-px-5 gl-py-4' }) do |c|
- c.with_header do - c.with_header do
.gl-new-card-title-wrapper .gl-flex.gl-grow
%h4.gl-new-card-title= s_('GroupSettings|Export group') %h4.gl-text-base.gl-leading-24.gl-m-0= s_('GroupSettings|Export group')
%p.gl-new-card-description %p.gl-text-subtle.gl-text-sm.gl-m-0
= _('Export this group with all related data.') = _('Export this group with all related data.')
- c.with_body do - c.with_body do

View File

@ -1,11 +1,11 @@
- form_id = "transfer-group-form" - form_id = "transfer-group-form"
- initial_data = { button_text: s_('GroupSettings|Transfer group'), group_full_path: @group.full_path, group_name: @group.name, group_id: @group.id, target_form_id: form_id, is_paid_group: group.paid?.to_s } - initial_data = { button_text: s_('GroupSettings|Transfer group'), group_full_path: @group.full_path, group_name: @group.name, group_id: @group.id, target_form_id: form_id, is_paid_group: group.paid?.to_s }
= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card', data: { testid: 'transfer-group-content' } }, header_options: { class: 'gl-new-card-header gl-flex-direction-column' }, body_options: { class: 'gl-new-card-body gl-px-5 gl-py-4' }) do |c| = render Pajamas::CardComponent.new(card_options: { data: { testid: 'transfer-group-content' } }, header_options: { class: 'gl-px-5 gl-py-4 gl-border-b-1 gl-border-b-solid gl-border-gray-100' }, body_options: { class: 'gl-px-5 gl-py-4' }) do |c|
- c.with_header do - c.with_header do
.gl-new-card-title-wrapper .gl-flex.gl-grow
%h4.gl-new-card-title.warning-title= s_('GroupSettings|Transfer group') %h4.gl-text-base.gl-leading-24.gl-m-0= s_('GroupSettings|Transfer group')
%p.gl-new-card-description %p.gl-text-subtle.gl-text-sm.gl-m-0
= _('Transfer group to another parent group.') = _('Transfer group to another parent group.')
- c.with_body do - c.with_body do

View File

@ -38,3 +38,6 @@
%ol#commits-list.list-unstyled.content_list %ol#commits-list.list-unstyled.content_list
= render 'commits', project: @project, ref: @ref = render 'commits', project: @project, ref: @ref
= gl_loading_icon(size: 'lg', css_class: 'loading hide') = gl_loading_icon(size: 'lg', css_class: 'loading hide')
-# https://gitlab.com/gitlab-org/gitlab/-/issues/408388#note_1578533983
#js-ambiguous-ref-modal{ data: { ambiguous: @is_ambiguous_ref.to_s, ref: current_ref } }

View File

@ -1,8 +0,0 @@
---
name: enable_environments_search_within_folder
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102227/diffs
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382108
milestone: '15.7'
type: development
group: group::environments
default_enabled: true

View File

@ -0,0 +1,9 @@
---
name: rules_exist_expand_globs_early
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/386595
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/160446
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/477245
milestone: '17.3'
group: group::pipeline authoring
type: gitlab_com_derisk
default_enabled: false

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddEncodedFilePathToMergeRequestDiffFiles < Gitlab::Database::Migration[2.2]
milestone '17.3'
def change
add_column :merge_request_diff_files, :encoded_file_path, :boolean, default: false, null: false
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddEncodedFilePathToMergeRequestContextCommitDiffFiles < Gitlab::Database::Migration[2.2]
milestone '17.3'
def change
add_column :merge_request_context_commit_diff_files, :encoded_file_path, :boolean, default: false, null: false
end
end

View File

@ -0,0 +1,47 @@
# frozen_string_literal: true
class AddAsyncFkUpstreamPipelineIdForPCiBuilds < Gitlab::Database::Migration[2.2]
include Gitlab::Database::PartitioningMigrationHelpers::ForeignKeyHelpers
milestone '17.3'
disable_ddl_transaction!
SOURCE_TABLE_NAME = :p_ci_builds
TARGET_TABLE_NAME = :ci_pipelines
COLUMN = :upstream_pipeline_id
PARTITION_COLUMN = :upstream_pipeline_partition_id
TARGET_COLUMN = :id
TARGET_PARTITION_COLUMN = :partition_id
FK_NAME = :fk_87f4cefcda_p
def up
add_concurrent_partitioned_foreign_key(
SOURCE_TABLE_NAME,
TARGET_TABLE_NAME,
column: [PARTITION_COLUMN, COLUMN],
target_column: [TARGET_PARTITION_COLUMN, TARGET_COLUMN],
validate: false,
reverse_lock_order: true,
on_update: :cascade,
on_delete: :cascade,
name: FK_NAME
)
prepare_partitioned_async_foreign_key_validation(SOURCE_TABLE_NAME, [PARTITION_COLUMN, COLUMN], name: FK_NAME)
end
def down
unprepare_partitioned_async_foreign_key_validation(SOURCE_TABLE_NAME, [PARTITION_COLUMN, COLUMN], name: FK_NAME)
Gitlab::Database::PostgresPartitionedTable.each_partition(SOURCE_TABLE_NAME) do |partition|
with_lock_retries do
remove_foreign_key_if_exists(
partition.identifier,
TARGET_TABLE_NAME,
name: FK_NAME,
reverse_lock_order: true
)
end
end
end
end

View File

@ -0,0 +1 @@
8369bef865b654e7222225f97529689ad13dfffb3ec97788e8771131fcfbe20c

View File

@ -0,0 +1 @@
6ba7d1d32d06384d282e760725a43112b6ff3c672b23f3dec384037988b3777e

View File

@ -0,0 +1 @@
819496fa89d7c3c8e2358dff44833d933db280fb0e0f45a870e362f776b68581

View File

@ -12648,7 +12648,8 @@ CREATE TABLE merge_request_context_commit_diff_files (
diff text, diff text,
"binary" boolean, "binary" boolean,
merge_request_context_commit_id bigint NOT NULL, merge_request_context_commit_id bigint NOT NULL,
generated boolean generated boolean,
encoded_file_path boolean DEFAULT false NOT NULL
); );
CREATE TABLE merge_request_context_commits ( CREATE TABLE merge_request_context_commits (
@ -12743,7 +12744,8 @@ CREATE TABLE merge_request_diff_files (
"binary" boolean, "binary" boolean,
external_diff_offset integer, external_diff_offset integer,
external_diff_size integer, external_diff_size integer,
generated boolean generated boolean,
encoded_file_path boolean DEFAULT false NOT NULL
); );
CREATE TABLE merge_request_diffs ( CREATE TABLE merge_request_diffs (
@ -33004,6 +33006,9 @@ ALTER TABLE ONLY packages_package_files
ALTER TABLE p_ci_builds ALTER TABLE p_ci_builds
ADD CONSTRAINT fk_87f4cefcda FOREIGN KEY (upstream_pipeline_id) REFERENCES ci_pipelines(id) ON DELETE CASCADE; ADD CONSTRAINT fk_87f4cefcda FOREIGN KEY (upstream_pipeline_id) REFERENCES ci_pipelines(id) ON DELETE CASCADE;
ALTER TABLE ONLY ci_builds
ADD CONSTRAINT fk_87f4cefcda_p FOREIGN KEY (upstream_pipeline_partition_id, upstream_pipeline_id) REFERENCES ci_pipelines(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE NOT VALID;
ALTER TABLE ONLY approval_group_rules_users ALTER TABLE ONLY approval_group_rules_users
ADD CONSTRAINT fk_888a0df3b7 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ADD CONSTRAINT fk_888a0df3b7 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;

View File

@ -51,6 +51,7 @@ Deployments show up in this list only after a deployment job has created them.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10754) in GitLab 15.5. > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10754) in GitLab 15.5.
> - [Searching environments within a folder](https://gitlab.com/gitlab-org/gitlab/-/issues/373850) was introduced in GitLab 15.7 with [Feature flag `enable_environments_search_within_folder`](https://gitlab.com/gitlab-org/gitlab/-/issues/382108). Enabled by default. > - [Searching environments within a folder](https://gitlab.com/gitlab-org/gitlab/-/issues/373850) was introduced in GitLab 15.7 with [Feature flag `enable_environments_search_within_folder`](https://gitlab.com/gitlab-org/gitlab/-/issues/382108). Enabled by default.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/382108) in GitLab 17.4. Feature flag `enable_environments_search_within_folder` removed.
To search environments by name: To search environments by name:

View File

@ -2892,6 +2892,7 @@ To implement signing:
security: { security: {
authn_requests_signed: true, # enable signature on AuthNRequest authn_requests_signed: true, # enable signature on AuthNRequest
want_assertions_signed: true, # enable the requirement of signed assertion want_assertions_signed: true, # enable the requirement of signed assertion
want_assertions_encrypted: false, # enable the requirement of encrypted assertion
metadata_signed: false, # enable signature on Metadata metadata_signed: false, # enable signature on Metadata
signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256', digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256',
@ -2926,6 +2927,7 @@ To implement signing:
security: security:
authn_requests_signed: true # enable signature on AuthNRequest authn_requests_signed: true # enable signature on AuthNRequest
want_assertions_signed: true # enable the requirement of signed assertion want_assertions_signed: true # enable the requirement of signed assertion
want_assertions_encrypted: false # enable the requirement of encrypted assertion
metadata_signed: false # enable signature on Metadata metadata_signed: false # enable signature on Metadata
signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256' signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256' digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256'
@ -2983,6 +2985,7 @@ To implement signing:
security: { security: {
authn_requests_signed: true, # enable signature on AuthNRequest authn_requests_signed: true, # enable signature on AuthNRequest
want_assertions_signed: true, # enable the requirement of signed assertion want_assertions_signed: true, # enable the requirement of signed assertion
want_assertions_encrypted: false, # enable the requirement of encrypted assertion
metadata_signed: false, # enable signature on Metadata metadata_signed: false, # enable signature on Metadata
signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256', digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256',
@ -3019,6 +3022,7 @@ To implement signing:
security: { security: {
authn_requests_signed: true, # enable signature on AuthNRequest authn_requests_signed: true, # enable signature on AuthNRequest
want_assertions_signed: true, # enable the requirement of signed assertion want_assertions_signed: true, # enable the requirement of signed assertion
want_assertions_encrypted: false, # enable the requirement of encrypted assertion
metadata_signed: false, # enable signature on Metadata metadata_signed: false, # enable signature on Metadata
signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256', digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256',

View File

@ -10,7 +10,7 @@ DETAILS:
**Tier:** Ultimate **Tier:** Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated **Offering:** GitLab.com, Self-managed, GitLab Dedicated
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/13266) in GitLab 17.2 [with a flag](../../../administration/feature_flags.md) named `pipeline_execution_policy_type`. Enabled by default. > - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/13266) in GitLab 17.2 [with a flag](../../../administration/feature_flags.md) named `pipeline_execution_policy_type`. Enabled by default. [Feature flag removed in GitLab 17.3](https://gitlab.com/gitlab-org/gitlab/-/issues/454278).
FLAG: FLAG:
The availability of this feature is controlled by a feature flag. The availability of this feature is controlled by a feature flag.

View File

@ -105,7 +105,7 @@ To troubleshoot a failed CI/CD job:
1. Select the failed CI/CD job. 1. Select the failed CI/CD job.
1. From the job log page, do one of the following: 1. From the job log page, do one of the following:
- Above the job log, select **Troubleshoot**. - Below the job log, select **Troubleshoot**.
- Open GitLab Duo Chat and type `/troubleshoot`. - Open GitLab Duo Chat and type `/troubleshoot`.
An analysis of the reasons for the failure and an example fix is displayed. An analysis of the reasons for the failure and an example fix is displayed.

View File

@ -2,3 +2,4 @@ include:
- local: gems/gem.gitlab-ci.yml - local: gems/gem.gitlab-ci.yml
inputs: inputs:
gem_name: "activerecord-gitlab" gem_name: "activerecord-gitlab"
bundle_gemfiles: ['Gemfile', 'Gemfile.next']

View File

@ -3,3 +3,5 @@
source "https://rubygems.org" source "https://rubygems.org"
gemspec gemspec
gem 'activerecord', '~> 7.0.8' # rubocop:disable Gemfile/MissingFeatureCategory

View File

@ -7,12 +7,12 @@ PATH
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
activemodel (7.0.6) activemodel (7.0.8.4)
activesupport (= 7.0.6) activesupport (= 7.0.8.4)
activerecord (7.0.6) activerecord (7.0.8.4)
activemodel (= 7.0.6) activemodel (= 7.0.8.4)
activesupport (= 7.0.6) activesupport (= 7.0.8.4)
activesupport (7.0.6) activesupport (7.0.8.4)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2) i18n (>= 1.6, < 2)
minitest (>= 5.1) minitest (>= 5.1)
@ -93,6 +93,7 @@ PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
activerecord (~> 7.0.8)
activerecord-gitlab! activerecord-gitlab!
gitlab-styles (~> 10.1.0) gitlab-styles (~> 10.1.0)
rspec (~> 3.12) rspec (~> 3.12)

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
source "https://rubygems.org"
gemspec
gem 'activerecord', '~> 7.1' # rubocop:disable Gemfile/MissingFeatureCategory

View File

@ -0,0 +1,131 @@
PATH
remote: .
specs:
activerecord-gitlab (0.2.0)
activerecord (>= 7)
GEM
remote: https://rubygems.org/
specs:
activemodel (7.1.3.4)
activesupport (= 7.1.3.4)
activerecord (7.1.3.4)
activemodel (= 7.1.3.4)
activesupport (= 7.1.3.4)
timeout (>= 0.4.0)
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)
ast (2.4.2)
base64 (0.2.0)
bigdecimal (3.1.8)
concurrent-ruby (1.3.3)
connection_pool (2.4.1)
diff-lcs (1.5.1)
drb (2.2.1)
gitlab-styles (10.1.0)
rubocop (~> 1.50.2)
rubocop-graphql (~> 0.18)
rubocop-performance (~> 1.15)
rubocop-rails (~> 2.17)
rubocop-rspec (~> 2.22)
i18n (1.14.5)
concurrent-ruby (~> 1.0)
json (2.7.2)
minitest (5.24.1)
mutex_m (0.2.0)
parallel (1.25.1)
parser (3.3.4.0)
ast (~> 2.4.1)
racc
racc (1.8.1)
rack (3.1.7)
rainbow (3.1.1)
regexp_parser (2.9.2)
rexml (3.3.4)
strscan
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.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.1)
rubocop (1.50.2)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.2.0.0)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.28.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.31.3)
parser (>= 3.3.1.0)
rubocop-capybara (2.21.0)
rubocop (~> 1.41)
rubocop-factory_bot (2.26.0)
rubocop (~> 1.41)
rubocop-graphql (0.19.0)
rubocop (>= 0.87, < 2)
rubocop-performance (1.21.1)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rails (2.25.1)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rspec (2.31.0)
rubocop (~> 1.40)
rubocop-capybara (~> 2.17)
rubocop-factory_bot (~> 2.22)
rubocop-rspec_rails (~> 2.28)
rubocop-rspec_rails (2.29.0)
rubocop (~> 1.40)
ruby-progressbar (1.13.0)
sqlite3 (1.7.3-aarch64-linux)
sqlite3 (1.7.3-arm-linux)
sqlite3 (1.7.3-arm64-darwin)
sqlite3 (1.7.3-x86-linux)
sqlite3 (1.7.3-x86_64-darwin)
sqlite3 (1.7.3-x86_64-linux)
strscan (3.1.0)
timeout (0.4.1)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.5.0)
PLATFORMS
aarch64-linux
arm-linux
arm64-darwin
x86-linux
x86_64-darwin
x86_64-linux
DEPENDENCIES
activerecord (~> 7.1)
activerecord-gitlab!
gitlab-styles (~> 10.1.0)
rspec (~> 3.12)
rubocop (~> 1.50)
rubocop-rspec (~> 2.22)
sqlite3 (~> 1.6)
BUNDLED WITH
2.5.11

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
if ::ActiveRecord::VERSION::STRING >= "7.1" if ::ActiveRecord::VERSION::STRING >= "7.2"
raise 'New version of active-record detected, please remove or update this patch' raise 'New version of active-record detected, please remove or update this patch'
end end
@ -9,6 +9,7 @@ module ActiveRecord
module GitlabPatches module GitlabPatches
module Partitioning module Partitioning
module Base module Base
if ::ActiveRecord::VERSION::STRING <= "7.1"
def _query_constraints_hash def _query_constraints_hash
if self.class.query_constraints_list.nil? if self.class.query_constraints_list.nil?
{ @primary_key => id_in_database } { @primary_key => id_in_database }
@ -18,6 +19,7 @@ module ActiveRecord
end end
end end
end end
end
module ClassMethods module ClassMethods
def query_constraints(*columns_list) def query_constraints(*columns_list)
@ -26,6 +28,7 @@ module ActiveRecord
@query_constraints_list = columns_list.map(&:to_s) @query_constraints_list = columns_list.map(&:to_s)
end end
if ::ActiveRecord::VERSION::STRING <= "7.1"
def query_constraints_list # :nodoc: def query_constraints_list # :nodoc:
@query_constraints_list ||= if base_class? || primary_key != base_class.primary_key @query_constraints_list ||= if base_class? || primary_key != base_class.primary_key
primary_key if primary_key.is_a?(Array) primary_key if primary_key.is_a?(Array)
@ -37,5 +40,6 @@ module ActiveRecord
end end
end end
end end
end
end end
# rubocop:enable Gitlab/ModuleWithInstanceVariables # rubocop:enable Gitlab/ModuleWithInstanceVariables

View File

@ -33,7 +33,7 @@ RSpec.describe 'ActiveRecord::GitlabPatches::Partitioning::Associations::Belongs
result = QueryRecorder.log do result = QueryRecorder.log do
job.build_pipeline.save! job.build_pipeline.save!
end end.join
expect(result).to include(create_statement) expect(result).to include(create_statement)
end end
@ -45,7 +45,7 @@ RSpec.describe 'ActiveRecord::GitlabPatches::Partitioning::Associations::Belongs
result = QueryRecorder.log do result = QueryRecorder.log do
job.create_pipeline! job.create_pipeline!
end end.join
expect(result).to include(create_statement) expect(result).to include(create_statement)
end end

View File

@ -52,7 +52,7 @@ RSpec.describe 'ActiveRecord::GitlabPatches::Partitioning::Associations::HasMany
result = QueryRecorder.log do result = QueryRecorder.log do
build = pipeline.jobs.new(name: 'test job') build = pipeline.jobs.new(name: 'test job')
build.save! build.save!
end end.join
expect(result).to include(create_statement) expect(result).to include(create_statement)
end end
@ -65,7 +65,7 @@ RSpec.describe 'ActiveRecord::GitlabPatches::Partitioning::Associations::HasMany
result = QueryRecorder.log do result = QueryRecorder.log do
pipeline.jobs.create!(name: 'test job') pipeline.jobs.create!(name: 'test job')
end end.join
expect(result).to include(create_statement) expect(result).to include(create_statement)
end end

View File

@ -34,7 +34,7 @@ RSpec.describe 'ActiveRecord::GitlabPatches::Partitioning::Associations::HasOne'
result = QueryRecorder.log do result = QueryRecorder.log do
job.build_metadata.save! job.build_metadata.save!
end end.join
expect(result).to include(create_statement) expect(result).to include(create_statement)
end end
@ -46,7 +46,7 @@ RSpec.describe 'ActiveRecord::GitlabPatches::Partitioning::Associations::HasOne'
result = QueryRecorder.log do result = QueryRecorder.log do
job.create_metadata job.create_metadata
end end.join
expect(result).to include(create_statement) expect(result).to include(create_statement)
end end
@ -92,7 +92,7 @@ RSpec.describe 'ActiveRecord::GitlabPatches::Partitioning::Associations::HasOne'
result = QueryRecorder.log do result = QueryRecorder.log do
job.save! job.save!
end end.join
update_statements.each do |statement| update_statements.each do |statement|
expect(result).to include(statement) expect(result).to include(statement)

View File

@ -13,7 +13,7 @@ RSpec.describe 'ActiveRecord::GitlabPatches::Partitioning::Associations::SingleM
result = QueryRecorder.log do result = QueryRecorder.log do
Job.create!(pipeline_id: pipeline.id, partition_id: pipeline.partition_id) Job.create!(pipeline_id: pipeline.id, partition_id: pipeline.partition_id)
end end.join
expect(result).to include(create_statement) expect(result).to include(create_statement)
end end

View File

@ -8,6 +8,9 @@
spec: spec:
inputs: inputs:
gem_name: gem_name:
bundle_gemfiles:
type: array
default: ['Gemfile']
gem_path_prefix: gem_path_prefix:
default: "gems/" default: "gems/"
skip_gem_validation: skip_gem_validation:
@ -54,6 +57,12 @@ default:
matrix: matrix:
- RUBY_VERSION: ["${RUBY_VERSION_DEFAULT}", "${RUBY_VERSION_NEXT}"] - RUBY_VERSION: ["${RUBY_VERSION_DEFAULT}", "${RUBY_VERSION_NEXT}"]
.ruby_on_rails_matrix:
parallel:
matrix:
- RUBY_VERSION: ["${RUBY_VERSION_DEFAULT}", "${RUBY_VERSION_NEXT}"]
- BUNDLE_GEMFILE: $[[inputs.bundle_gemfiles]]
validate-gem: validate-gem:
rules: rules:
- if: "'$[[inputs.skip_gem_validation]]' == 'true'" - if: "'$[[inputs.skip_gem_validation]]' == 'true'"
@ -71,7 +80,7 @@ rubocop:
- bundle exec rubocop - bundle exec rubocop
rspec: rspec:
extends: .ruby_matrix extends: .ruby_on_rails_matrix
script: script:
- RAILS_ENV=test bundle exec rspec - RAILS_ENV=test bundle exec rspec
coverage: '/LOC \((\d+\.\d+%)\) covered.$/' coverage: '/LOC \((\d+\.\d+%)\) covered.$/'

View File

@ -861,7 +861,11 @@ module API
env['api.format'] = :txt env['api.format'] = :txt
content_type 'text/plain' content_type 'text/plain'
header['Content-Disposition'] = ActionDispatch::Http::ContentDisposition.format(disposition: 'inline', filename: blob.name) # Some browsers ignore content type when filename has an xhtml extension
# We remove the extensions to prevent the contents from being displayed inline
# See https://gitlab.com/gitlab-org/gitlab/-/issues/458236
filename = blob.name&.ends_with?('.xhtml') ? blob.name.split('.')[0] : blob.name
header['Content-Disposition'] = ActionDispatch::Http::ContentDisposition.format(disposition: 'inline', filename: filename)
# Let Workhorse examine the content and determine the better content disposition # Let Workhorse examine the content and determine the better content disposition
header[Gitlab::Workhorse::DETECT_HEADER] = "true" header[Gitlab::Workhorse::DETECT_HEADER] = "true"

View File

@ -149,7 +149,7 @@ module API
actor.update_last_used_at! actor.update_last_used_at!
Gitlab::LfsToken Gitlab::LfsToken
.new(actor.key_or_user) .new(actor.key_or_user, container)
.authentication_payload(lfs_authentication_url(container)) .authentication_payload(lfs_authentication_url(container))
end end

View File

@ -2,8 +2,16 @@
module Banzai module Banzai
module Filter module Filter
# The maximum number of items that a filter should allow,
# such as emojis, etc.
FILTER_ITEM_LIMIT = 1000
def self.[](name) def self.[](name)
const_get("#{name.to_s.camelize}Filter", false) const_get("#{name.to_s.camelize}Filter", false)
end end
def self.filter_item_limit_exceeded?(count)
count >= FILTER_ITEM_LIMIT
end
end end
end end

View File

@ -35,14 +35,15 @@ module Banzai
end end
def custom_emoji_name_element_filter(text) def custom_emoji_name_element_filter(text)
text.gsub(custom_emoji_pattern) do |match| Gitlab::Utils::Gsub
name = Regexp.last_match[1] .gsub_with_limit(text, custom_emoji_pattern, limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match_data|
name = match_data[1]
custom_emoji = all_custom_emoji[name] custom_emoji = all_custom_emoji[name]
if custom_emoji if custom_emoji
Gitlab::Emoji.custom_emoji_tag(custom_emoji.name, custom_emoji.url) Gitlab::Emoji.custom_emoji_tag(custom_emoji.name, custom_emoji.url)
else else
match match_data[0]
end end
end end
end end

View File

@ -12,19 +12,16 @@ module Banzai
IGNORED_ANCESTOR_TAGS = %w[pre code tt].to_set IGNORED_ANCESTOR_TAGS = %w[pre code tt].to_set
# Limit of how many emojis we will process.
# Protects against pathological number of emojis.
# For more information check: https://gitlab.com/gitlab-org/gitlab/-/issues/434803
EMOJI_LIMIT = 1000
def call_with_timeout def call_with_timeout
@emoji_count = 0 @emoji_count = 0
doc.xpath('descendant-or-self::text()').each do |node| doc.xpath('descendant-or-self::text()').each do |node|
content = node.to_html break if Banzai::Filter.filter_item_limit_exceeded?(@emoji_count)
next if has_ancestor?(node, IGNORED_ANCESTOR_TAGS) next if has_ancestor?(node, IGNORED_ANCESTOR_TAGS)
next unless content.include?(':') || node.text.match(emoji_unicode_pattern) content = node.to_html
next unless content.include?(':') || emoji_unicode_pattern_untrusted.match?(content)
html = emoji_unicode_element_unicode_filter(content) html = emoji_unicode_element_unicode_filter(content)
html = emoji_name_element_unicode_filter(html) html = emoji_name_element_unicode_filter(html)
@ -43,8 +40,12 @@ module Banzai
# #
# Returns a String with :emoji: replaced with gl-emoji unicode. # Returns a String with :emoji: replaced with gl-emoji unicode.
def emoji_name_element_unicode_filter(text) def emoji_name_element_unicode_filter(text)
scan_and_replace(text, emoji_pattern) do |matched_text| Gitlab::Utils::Gsub
TanukiEmoji.find_by_alpha_code(matched_text) .gsub_with_limit(text, emoji_pattern, limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match_data|
emoji = TanukiEmoji.find_by_alpha_code(match_data[0])
@emoji_count += 1 if emoji
Gitlab::Emoji.gl_emoji_tag(emoji) if emoji
end end
end end
@ -54,8 +55,11 @@ module Banzai
# #
# Returns a String with unicode emoji replaced with gl-emoji unicode. # Returns a String with unicode emoji replaced with gl-emoji unicode.
def emoji_unicode_element_unicode_filter(text) def emoji_unicode_element_unicode_filter(text)
scan_and_replace(text, emoji_unicode_pattern) do |matched_text| emoji_unicode_pattern_untrusted.replace_gsub(text, limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match|
TanukiEmoji.find_by_codepoints(matched_text) emoji = TanukiEmoji.find_by_codepoints(match[1])
@emoji_count += 1 if emoji
Gitlab::Emoji.gl_emoji_tag(emoji) if emoji
end end
end end
@ -64,56 +68,22 @@ module Banzai
@emoji_pattern ||= TanukiEmoji.index.alpha_code_pattern @emoji_pattern ||= TanukiEmoji.index.alpha_code_pattern
end end
# Build a regexp that matches all valid unicode emojis names. # Build an unstrusted regexp that matches all valid unicode emojis names.
def self.emoji_unicode_pattern def self.emoji_unicode_pattern_untrusted
@emoji_unicode_pattern ||= TanukiEmoji.index.codepoints_pattern return @emoji_unicode_pattern_untrusted if @emoji_unicode_pattern_untrusted
source = TanukiEmoji.index.codepoints_pattern.source
@emoji_unicode_pattern_untrusted = Gitlab::UntrustedRegexp.new(source)
end end
private private
# This performs the same function as a `gsub`. However this version
# allows us to break out of the replacement loop when the limit is
# reached. Benchmarking showed performance was roughly equivalent.
def scan_and_replace(text, pattern)
scanner = StringScanner.new(text)
buffer = +''
return text unless scanner.exist?(pattern)
until scanner.eos?
portion = scanner.scan_until(pattern)
if portion.nil?
buffer << scanner.rest
scanner.terminate
break
end
if emoji_limit_reached?(@emoji_count)
buffer << portion
buffer << scanner.rest
scanner.terminate
break
end
emoji = yield(scanner.matched)
@emoji_count += 1 if emoji
buffer << portion.sub(scanner.matched, Gitlab::Emoji.gl_emoji_tag(emoji))
end
buffer
end
def emoji_pattern def emoji_pattern
self.class.emoji_pattern self.class.emoji_pattern
end end
def emoji_unicode_pattern def emoji_unicode_pattern_untrusted
self.class.emoji_unicode_pattern self.class.emoji_unicode_pattern_untrusted
end
def emoji_limit_reached?(count)
count >= EMOJI_LIMIT
end end
end end
end end

View File

@ -8,7 +8,8 @@ module Banzai
def call def call
lang_mapping = Gitlab::FrontMatter::DELIM_LANG lang_mapping = Gitlab::FrontMatter::DELIM_LANG
Gitlab::FrontMatter::PATTERN_UNTRUSTED_REGEX.replace_gsub(html) do |match| Gitlab::FrontMatter::PATTERN_UNTRUSTED_REGEX
.replace_gsub(html, limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match|
lang = match[:lang].presence || lang_mapping[match[:delim]] lang = match[:lang].presence || lang_mapping[match[:delim]]
before = match[:before] before = match[:before]

View File

@ -41,7 +41,8 @@ module Banzai
next if has_ancestor?(node, IGNORED_ANCESTOR_TAGS) next if has_ancestor?(node, IGNORED_ANCESTOR_TAGS)
next unless TAGS_PATTERN_UNTRUSTED_REGEX.match?(node.content) next unless TAGS_PATTERN_UNTRUSTED_REGEX.match?(node.content)
html = TAGS_PATTERN_UNTRUSTED_REGEX.replace_gsub(CGI.escapeHTML(node.content)) do |match| html = TAGS_PATTERN_UNTRUSTED_REGEX
.replace_gsub(CGI.escapeHTML(node.content), limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match|
process_tag(CGI.unescapeHTML(match[1]))&.to_s || match[0] process_tag(CGI.unescapeHTML(match[1]))&.to_s || match[0]
end end

View File

@ -31,11 +31,13 @@ module Banzai
end end
def inline_diff_filter(text) def inline_diff_filter(text)
html_content = INLINE_DIFF_DELETION_UNTRUSTED_REGEX.replace_gsub(text) do |match| html_content = INLINE_DIFF_DELETION_UNTRUSTED_REGEX
.replace_gsub(text, limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match|
%(<span class="idiff left right deletion">#{match[1]}#{match[2]}</span>) %(<span class="idiff left right deletion">#{match[1]}#{match[2]}</span>)
end end
INLINE_DIFF_ADDITION_UNTRUSTED_REGEX.replace_gsub(html_content) do |match| INLINE_DIFF_ADDITION_UNTRUSTED_REGEX
.replace_gsub(html_content, limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match|
%(<span class="idiff left right addition">#{match[1]}#{match[2]}</span>) %(<span class="idiff left right addition">#{match[1]}#{match[2]}</span>)
end end
end end

View File

@ -39,11 +39,12 @@ module Banzai
# #
# Returns a String replaced with the return of the block. # Returns a String replaced with the return of the block.
def references_in(text, pattern = object_class.reference_pattern) def references_in(text, pattern = object_class.reference_pattern)
text.gsub(pattern) do |match| Gitlab::Utils::Gsub.gsub_with_limit(text, pattern, limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match_data|
if ident = identifier($~) if ident = identifier(match_data)
yield match, ident, $~.named_captures['project'], $~.named_captures['namespace'], $~ yield match_data[0], ident, match_data.named_captures['project'], match_data.named_captures['namespace'],
match_data
else else
match match_data[0]
end end
end end
end end

View File

@ -11,8 +11,9 @@ module Banzai
self.object_class = CommitRange self.object_class = CommitRange
def references_in(text, pattern = object_reference_pattern) def references_in(text, pattern = object_reference_pattern)
text.gsub(pattern) do |match| Gitlab::Utils::Gsub.gsub_with_limit(text, pattern, limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match_data|
yield match, $~[:commit_range], $~[:project], $~[:namespace], $~ yield match_data[0], match_data[:commit_range], match_data[:project], match_data[:namespace],
match_data
end end
end end

View File

@ -11,8 +11,9 @@ module Banzai
self.object_class = Commit self.object_class = Commit
def references_in(text, pattern = object_reference_pattern) def references_in(text, pattern = object_reference_pattern)
text.gsub(pattern) do |match| Gitlab::Utils::Gsub.gsub_with_limit(text, pattern, limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match_data|
yield match, $~[:commit], $~[:project], $~[:namespace], $~ yield match_data[0], match_data[:commit], match_data[:project], match_data[:namespace],
match_data
end end
end end

View File

@ -26,11 +26,11 @@ module Banzai
def references_in(text, pattern = object_reference_pattern) def references_in(text, pattern = object_reference_pattern)
case pattern case pattern
when Regexp when Regexp
text.gsub(pattern) do |match| Gitlab::Utils::Gsub.gsub_with_limit(text, pattern, limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match_data|
yield match, $~[:issue] yield match_data[0], match_data[:issue]
end end
when Gitlab::UntrustedRegexp when Gitlab::UntrustedRegexp
pattern.replace_gsub(text) do |match| pattern.replace_gsub(text, limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match|
yield match, match[:issue] yield match, match[:issue]
end end
end end

View File

@ -20,8 +20,8 @@ module Banzai
# #
# Returns a String replaced with the return of the block. # Returns a String replaced with the return of the block.
def references_in(text, pattern = object_reference_pattern) def references_in(text, pattern = object_reference_pattern)
text.gsub(pattern) do |match| Gitlab::Utils::Gsub.gsub_with_limit(text, pattern, limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match_data|
yield match, "#{$~[:namespace]}/#{$~[:project]}" yield match_data[0], "#{match_data[:namespace]}/#{match_data[:project]}"
end end
end end

View File

@ -100,6 +100,10 @@ module Banzai
@nodes ||= each_node.to_a @nodes ||= each_node.to_a
end end
def nodes?
@nodes.present?
end
def object_class def object_class
self.class.object_class self.class.object_class
end end
@ -296,6 +300,9 @@ module Banzai
# Once Filter completes replacing nodes, we update nodes with @new_nodes # Once Filter completes replacing nodes, we update nodes with @new_nodes
def update_nodes! def update_nodes!
# if we haven't loaded `nodes` yet, don't do it here
return unless nodes?
@new_nodes.sort_by { |index, _new_nodes| -index }.each do |index, new_nodes| @new_nodes.sort_by { |index, _new_nodes| -index }.each do |index, new_nodes|
nodes[index, 1] = new_nodes nodes[index, 1] = new_nodes
end end

View File

@ -22,8 +22,8 @@ module Banzai
# #
# Returns a String replaced with the return of the block. # Returns a String replaced with the return of the block.
def references_in(text, pattern = object_reference_pattern) def references_in(text, pattern = object_reference_pattern)
text.gsub(pattern) do |match| Gitlab::Utils::Gsub.gsub_with_limit(text, pattern, limit: Banzai::Filter::FILTER_ITEM_LIMIT) do |match_data|
yield match, $~[:user] yield match_data[0], match_data['user']
end end
end end

View File

@ -35,8 +35,14 @@ module Banzai
CSS_WIKILINK_STYLE = 'a[href][data-wikilink]' CSS_WIKILINK_STYLE = 'a[href][data-wikilink]'
XPATH_WIKILINK_STYLE = Gitlab::Utils::Nokogiri.css_to_xpath(CSS_WIKILINK_STYLE).freeze XPATH_WIKILINK_STYLE = Gitlab::Utils::Nokogiri.css_to_xpath(CSS_WIKILINK_STYLE).freeze
IMAGE_LINK_LIMIT = 100
def call def call
doc.xpath(XPATH_WIKILINK_STYLE).each do |node| @image_link_count = 0
doc.xpath(XPATH_WIKILINK_STYLE).each_with_index do |node, index|
break if Banzai::Filter.filter_item_limit_exceeded?(index)
process_image_link(node) || process_page_link(node) process_image_link(node) || process_page_link(node)
end end
@ -49,10 +55,14 @@ module Banzai
def process_image_link(node) def process_image_link(node)
return unless image?(node[:href]) return unless image?(node[:href])
# checking for the existence of an image file tends to be slow. So limit it.
return if image_link_limit_exceeded?
path = path =
if url?(node[:href]) if url?(node[:href])
node[:href] node[:href]
elsif wiki elsif wiki
@image_link_count += 1
wiki.find_file(node[:href], load_content: false)&.path wiki.find_file(node[:href], load_content: false)&.path
end end
@ -106,6 +116,10 @@ module Banzai
def url?(path) def url?(path)
path.start_with?(*%w[http https]) path.start_with?(*%w[http https])
end end
def image_link_limit_exceeded?
@image_link_count >= Banzai::Filter::WikiLinkGollumFilter::IMAGE_LINK_LIMIT
end
end end
end end
end end

View File

@ -13,7 +13,11 @@ module Gitlab
# Parser/renderer for the AsciiDoc format that uses Asciidoctor and filters # Parser/renderer for the AsciiDoc format that uses Asciidoctor and filters
# the resulting HTML through HTML pipeline filters. # the resulting HTML through HTML pipeline filters.
module Asciidoc module Asciidoc
MAX_INCLUDE_DEPTH = 5 # This value ensures a safe depth limit on the number of included files when using include
# directives in Asciidoc. By considering the exponential growth effect that comes with
# depth, a lower number results in a controlled number of included files.
MAX_INCLUDE_DEPTH = 3
RENDER_TIMEOUT = 10.seconds
DEFAULT_ADOC_ATTRS = { DEFAULT_ADOC_ATTRS = {
'showtitle' => true, 'showtitle' => true,
'sectanchors' => true, 'sectanchors' => true,
@ -79,9 +83,14 @@ module Gitlab
Gitlab::Plantuml.configure Gitlab::Plantuml.configure
Gitlab::RenderTimeout.timeout(foreground: RENDER_TIMEOUT) do
html = ::Asciidoctor.convert(input, asciidoc_opts) html = ::Asciidoctor.convert(input, asciidoc_opts)
html = Banzai.render(html, context) html = Banzai.render(html, context)
html.html_safe html.html_safe
end end
rescue Timeout::Error => e
class_name = name.demodulize
Gitlab::ErrorTracking.track_exception(e, project_id: context[:project]&.id, class_name: class_name)
end
end end
end end

View File

@ -327,7 +327,7 @@ module Gitlab
return unless actor return unless actor
token_handler = Gitlab::LfsToken.new(actor) token_handler = Gitlab::LfsToken.new(actor, project)
authentication_abilities = authentication_abilities =
if token_handler.user? if token_handler.user?

View File

@ -99,7 +99,7 @@ module Gitlab
login, token = user_name_and_password(current_request) login, token = user_name_and_password(current_request)
user = User.find_by_login(login.to_s) user = User.find_by_login(login.to_s)
user if user && Gitlab::LfsToken.new(user).token_valid?(token.to_s) user if user && Gitlab::LfsToken.new(user, nil).token_valid?(token.to_s)
end end
def find_user_from_personal_access_token def find_user_from_personal_access_token

View File

@ -26,8 +26,16 @@ module Gitlab
context = change_context(context) if @project_path context = change_context(context) if @project_path
paths = worktree_paths(context) if Feature.enabled?(:rules_exist_expand_globs_early, context.project)
exact_globs, extension_globs, pattern_globs = separate_globs(context) expanded_globs = expand_globs(context)
top_level_only = expanded_globs.all?(&method(:top_level_glob?))
paths = worktree_paths(context, top_level_only)
exact_globs, extension_globs, pattern_globs = separate_globs(expanded_globs)
else
paths = worktree_paths_old(context)
exact_globs, extension_globs, pattern_globs = separate_globs_old(context)
end
exact_matches?(paths, exact_globs) || exact_matches?(paths, exact_globs) ||
matches_extension?(paths, extension_globs) || matches_extension?(paths, extension_globs) ||
@ -36,7 +44,12 @@ module Gitlab
private private
def separate_globs(context) def separate_globs(expanded_globs)
grouped = expanded_globs.group_by { |glob| glob_type(glob) }
grouped.values_at(:exact, :extension, :pattern).map { |globs| Array(globs) }
end
def separate_globs_old(context)
expanded_globs = expand_globs(context) expanded_globs = expand_globs(context)
grouped = expanded_globs.group_by { |glob| glob_type(glob) } grouped = expanded_globs.group_by { |glob| glob_type(glob) }
@ -49,7 +62,17 @@ module Gitlab
end end
end end
def worktree_paths(context) def worktree_paths(context, top_level_only)
return [] unless context.project
if top_level_only
context.top_level_worktree_paths
else
context.all_worktree_paths
end
end
def worktree_paths_old(context)
return [] unless context.project return [] unless context.project
if @top_level_only if @top_level_only

View File

@ -35,7 +35,7 @@ module Gitlab
# #
# Returns a Mode # Returns a Mode
def self.default def self.default
by_id(1) by_id(default_id)
end end
# Iterate through each Mode # Iterate through each Mode
@ -61,5 +61,12 @@ module Gitlab
def self.valid_ids def self.valid_ids
available_modes.map(&:id) available_modes.map(&:id)
end end
def self.default_id
@default_id ||= begin
id = Gitlab.config.gitlab['default_color_mode']&.to_i
available_modes.detect { |s| s.id == id }&.id || APPLICATION_DEFAULT
end
end
end end
end end

View File

@ -10,7 +10,7 @@ module Gitlab
attr_accessor :old_path, :new_path, :a_mode, :b_mode, :diff attr_accessor :old_path, :new_path, :a_mode, :b_mode, :diff
# Stats properties # Stats properties
attr_accessor :new_file, :renamed_file, :deleted_file, :generated attr_accessor :new_file, :renamed_file, :deleted_file, :generated, :encoded_file_path
alias_method :new_file?, :new_file alias_method :new_file?, :new_file
alias_method :deleted_file?, :deleted_file alias_method :deleted_file?, :deleted_file
@ -43,6 +43,7 @@ module Gitlab
deleted_file deleted_file
too_large too_large
generated generated
encoded_file_path
].freeze ].freeze
BINARY_NOTICE_PATTERN = %r{Binary files (.*) and (.*) differ} BINARY_NOTICE_PATTERN = %r{Binary files (.*) and (.*) differ}
@ -305,6 +306,8 @@ module Gitlab
@too_large = gitaly_diff.too_large if gitaly_diff.respond_to?(:too_large) @too_large = gitaly_diff.too_large if gitaly_diff.respond_to?(:too_large)
gitaly_overflow = gitaly_diff.try(:overflow_marker) gitaly_overflow = gitaly_diff.try(:overflow_marker)
@overflow = Diff.collect_patch_overage? && gitaly_overflow @overflow = Diff.collect_patch_overage? && gitaly_overflow
@encoded_file_path = file_path_encoded?(gitaly_diff.to_path, @new_path) ||
file_path_encoded?(gitaly_diff.from_path, @old_path)
collapse! if gitaly_diff.respond_to?(:collapsed) && gitaly_diff.collapsed collapse! if gitaly_diff.respond_to?(:collapsed) && gitaly_diff.collapsed
# Diffs exceeding limits returned from gitaly when "collect_all_paths" are enabled # Diffs exceeding limits returned from gitaly when "collect_all_paths" are enabled
@ -324,6 +327,18 @@ module Gitlab
collapse! collapse!
end end
end end
def file_path_encoded?(raw_path, encoded_path)
return false unless raw_path && encoded_path
# We need to compare paths in the same encoding as they won't be equal
# and return false positive when compared using different encoding.
#
# If the `encoded_path` was cleaned up (invalid UTF-8 characters were
# removed) during encoding, we can then consider that the file paths are
# no longer equal.
raw_path != encoded_path.dup.force_encoding(raw_path.encoding)
end
end end
end end
end end

View File

@ -457,6 +457,7 @@ included_attributes:
- :b_mode - :b_mode
- :too_large - :too_large
- :binary - :binary
- :encoded_file_path
metrics: metrics:
- :created_at - :created_at
- :updated_at - :updated_at

View File

@ -10,6 +10,10 @@ module Gitlab
def actor_name def actor_name
user? ? actor.username : "lfs+deploy-key-#{actor.id}" user? ? actor.username : "lfs+deploy-key-#{actor.id}"
end end
def container_gid
container ? container.to_gid.to_s : nil
end
end end
include LfsTokenHelper include LfsTokenHelper
@ -18,7 +22,7 @@ module Gitlab
attr_accessor :actor attr_accessor :actor
def initialize(actor) def initialize(actor, container)
@actor = @actor =
case actor case actor
when DeployKey, User when DeployKey, User
@ -28,17 +32,19 @@ module Gitlab
else else
raise 'Bad Actor' raise 'Bad Actor'
end end
@container = container
end end
def token def token
HMACToken.new(actor).token(DEFAULT_EXPIRE_TIME) HMACToken.new(actor, container).token(DEFAULT_EXPIRE_TIME)
end end
# When the token is an lfs one and the actor # When the token is an lfs one and the actor
# is blocked or the password has been changed, # is blocked or the password has been changed,
# the token is no longer valid # the token is no longer valid
def token_valid?(token_to_check) def token_valid?(token_to_check)
HMACToken.new(actor).token_valid?(token_to_check) && valid_user? HMACToken.new(actor, container).token_valid?(token_to_check) && valid_user?
end end
def deploy_key_pushable?(project) def deploy_key_pushable?(project)
@ -70,30 +76,40 @@ module Gitlab
private # rubocop:disable Lint/UselessAccessModifier private # rubocop:disable Lint/UselessAccessModifier
attr_reader :container
class HMACToken class HMACToken
include LfsTokenHelper include LfsTokenHelper
def initialize(actor) def initialize(actor, container)
@actor = actor @actor = actor
@container = container
end end
def token(expire_time) def token(expire_time)
hmac_token = JSONWebToken::HMACToken.new(secret) hmac_token = JSONWebToken::HMACToken.new(secret)
hmac_token.expire_time = Time.now + expire_time hmac_token.expire_time = Time.now + expire_time
hmac_token[:data] = { actor: actor_name } hmac_token[:data] = { actor: actor_name }
hmac_token[:data][:container_gid] = container_gid if container
hmac_token.encoded hmac_token.encoded
end end
def token_valid?(token_to_check) def token_valid?(token_to_check)
decoded_token = JSONWebToken::HMACToken.decode(token_to_check, secret).first decoded_token = JSONWebToken::HMACToken.decode(token_to_check, secret).first
decoded_token.dig('data', 'actor') == actor_name return false if decoded_token.dig('data', 'actor') != actor_name
token_container = decoded_token.dig('data', 'container_gid')
return true if token_container.blank? || container.blank?
token_container == container_gid
rescue JWT::DecodeError rescue JWT::DecodeError
false false
end end
private private
attr_reader :actor attr_reader :actor, :container
def secret def secret
case actor case actor

View File

@ -22,6 +22,11 @@ module Gitlab
} }
end end
# Rubocop requires this be public
def self.parameter_filter
@parameter_filter ||= ActiveSupport::ParameterFilter.new(Rails.application.config.filter_parameters)
end
def safelist(event) def safelist(event)
req = event.payload[:request] req = event.payload[:request]
Gitlab::Instrumentation::Throttle.safelist = req.env['rack.attack.matched'] Gitlab::Instrumentation::Throttle.safelist = req.env['rack.attack.matched']
@ -41,14 +46,23 @@ module Gitlab
private private
def parameter_filter
self.class.parameter_filter
end
def log_into_auth_logger(event, status:) def log_into_auth_logger(event, status:)
# req here is a Rack::Attack::Request, inherits from Rack::Request
# https://rubydoc.info/gems/rack/2.2.9/Rack/Request
req = event.payload[:request] req = event.payload[:request]
filtered_params = parameter_filter.filter(req.GET)
req_path = filtered_params.any? ? "#{req.path}?#{filtered_params.to_query}" : req.path
rack_attack_info = { rack_attack_info = {
message: 'Rack_Attack', message: 'Rack_Attack',
env: req.env['rack.attack.match_type'], env: req.env['rack.attack.match_type'],
remote_ip: req.ip, remote_ip: req.ip,
request_method: req.request_method, request_method: req.request_method,
path: req.fullpath, path: req_path,
matched: req.env['rack.attack.matched'] matched: req.env['rack.attack.matched']
} }

View File

@ -47,7 +47,7 @@ module Gitlab
mr: :merge_request mr: :merge_request
}).freeze }).freeze
OPTION_MATCHER = /(?<namespace>[^\.]+)\.(?<key>[^=]+)=?(?<value>.*)/ OPTION_MATCHER = Gitlab::UntrustedRegexp.new('(?<namespace>[^\.]+)\.(?<key>[^=]+)=?(?<value>.*)')
CI_SKIP = 'ci.skip' CI_SKIP = 'ci.skip'
@ -101,7 +101,10 @@ module Gitlab
parts = OPTION_MATCHER.match(option) parts = OPTION_MATCHER.match(option)
return unless parts return unless parts
namespace, key, value = parts.values_at(:namespace, :key, :value).map(&:strip) namespace = extract_match(parts, :namespace)
key = extract_match(parts, :key)
value = extract_match(parts, :value)
namespace = NAMESPACE_ALIASES[namespace] if NAMESPACE_ALIASES[namespace] namespace = NAMESPACE_ALIASES[namespace] if NAMESPACE_ALIASES[namespace]
value = value.presence || true value = value.presence || true
@ -110,6 +113,10 @@ module Gitlab
[namespace, key, value] [namespace, key, value]
end end
def extract_match(parts, key)
parts[key].to_s.strip
end
def valid_option?(namespace, key) def valid_option?(namespace, key)
keys = VALID_OPTIONS.dig(namespace, :keys) keys = VALID_OPTIONS.dig(namespace, :keys)
keys && keys.include?(key.to_sym) keys && keys.include?(key.to_sym)

View File

@ -39,9 +39,10 @@ module Gitlab
# There is no built-in replace with block support (like `gsub`). We can accomplish # There is no built-in replace with block support (like `gsub`). We can accomplish
# the same thing by parsing and rebuilding the string with the substitutions. # the same thing by parsing and rebuilding the string with the substitutions.
def replace_gsub(text) def replace_gsub(text, limit: 0)
new_text = +'' new_text = +''
remainder = text remainder = text
count = 0
matched = match(remainder) matched = match(remainder)
@ -52,6 +53,11 @@ module Gitlab
new_text << yield(matched) new_text << yield(matched)
if limit > 0
count += 1
break if count >= limit
end
matched = match(remainder) matched = match(remainder)
end end

36
lib/gitlab/utils/gsub.rb Normal file
View File

@ -0,0 +1,36 @@
# frozen_string_literal: true
module Gitlab
module Utils
module Gsub
extend self
# This performs the same basic function as a `gsub`. However this version
# allows us to break out of the replacement loop when the limit is reached.
# This is the same algorithm used for Gitlab::UntrustedRegexp.replace_gsub
def gsub_with_limit(text, pattern, limit:)
new_text = +''
remainder = text
count = 0
matched = remainder.match(pattern)
until matched.nil? || matched.to_a.compact.empty?
new_text << matched.pre_match
remainder = matched.post_match
new_text << (yield(matched) || '').to_s
if limit > 0
count += 1
break if count >= limit
end
matched = remainder.match(pattern)
end
new_text << remainder
end
end
end
end

View File

@ -2228,9 +2228,6 @@ msgstr ""
msgid "AI|Description is required" msgid "AI|Description is required"
msgstr "" msgstr ""
msgid "AI|Experiment"
msgstr ""
msgid "AI|Explain or Resolve with AI" msgid "AI|Explain or Resolve with AI"
msgstr "" msgstr ""
@ -17858,9 +17855,6 @@ msgstr ""
msgid "Dependencies|Filtering unavailable" msgid "Dependencies|Filtering unavailable"
msgstr "" msgstr ""
msgid "Dependencies|Job failed to generate the dependency list"
msgstr ""
msgid "Dependencies|Learn more about dependency paths" msgid "Dependencies|Learn more about dependency paths"
msgstr "" msgstr ""
@ -17891,9 +17885,6 @@ msgstr ""
msgid "Dependencies|Software Bill of Materials (SBOM) based on the latest successful scan of each project." msgid "Dependencies|Software Bill of Materials (SBOM) based on the latest successful scan of each project."
msgstr "" msgstr ""
msgid "Dependencies|The %{codeStartTag}dependency_scanning%{codeEndTag} job has failed and cannot generate the list. Please ensure the job is running properly and run the pipeline again."
msgstr ""
msgid "Dependencies|The component dependency path is based on the lock file. There may be several paths. In these cases, the longest path is displayed." msgid "Dependencies|The component dependency path is based on the lock file. There may be several paths. In these cases, the longest path is displayed."
msgstr "" msgstr ""
@ -17930,9 +17921,6 @@ msgstr ""
msgid "Dependencies|Unknown path" msgid "Dependencies|Unknown path"
msgstr "" msgstr ""
msgid "Dependencies|Unsupported file(s) detected"
msgstr ""
msgid "Dependencies|Vulnerable components" msgid "Dependencies|Vulnerable components"
msgstr "" msgstr ""
@ -21852,30 +21840,6 @@ msgstr ""
msgid "Experiment features' settings not allowed." msgid "Experiment features' settings not allowed."
msgstr "" msgstr ""
msgid "ExperimentBadge|An experiment is not yet production-ready, but is released for initial testing and feedback during development."
msgstr ""
msgid "ExperimentBadge|Are not supported and might not be documented."
msgstr ""
msgid "ExperimentBadge|Are subject to the GitLab Testing Agreement."
msgstr ""
msgid "ExperimentBadge|Could be changed or removed at any time."
msgstr ""
msgid "ExperimentBadge|Experiment"
msgstr ""
msgid "ExperimentBadge|Experiments:"
msgstr ""
msgid "ExperimentBadge|Might be unstable or cause data loss."
msgstr ""
msgid "ExperimentBadge|What's an experiment?"
msgstr ""
msgid "Experiments" msgid "Experiments"
msgstr "" msgstr ""
@ -30314,9 +30278,6 @@ msgstr ""
msgid "Job|Failed" msgid "Job|Failed"
msgstr "" msgstr ""
msgid "Job|Feedback issue"
msgstr ""
msgid "Job|Finished at" msgid "Job|Finished at"
msgstr "" msgstr ""
@ -30326,6 +30287,9 @@ msgstr ""
msgid "Job|Full screen mode is not available" msgid "Job|Full screen mode is not available"
msgstr "" msgstr ""
msgid "Job|Give feedback"
msgstr ""
msgid "Job|Job artifacts" msgid "Job|Job artifacts"
msgstr "" msgstr ""
@ -36412,12 +36376,6 @@ msgstr ""
msgid "Observability|Enable tracing, metrics, or logs on your project." msgid "Observability|Enable tracing, metrics, or logs on your project."
msgstr "" msgstr ""
msgid "Observability|Error: Failed to enable GitLab Observability. Please retry later."
msgstr ""
msgid "Observability|Error: Failed to load page. Try reloading the page."
msgstr ""
msgid "Observability|Failed to load observability usage data." msgid "Observability|Failed to load observability usage data."
msgstr "" msgstr ""
@ -36938,9 +36896,6 @@ msgstr ""
msgid "One or more of your %{provider} projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git." msgid "One or more of your %{provider} projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git."
msgstr "" msgstr ""
msgid "One or more of your dependency files are not supported, and the dependency list may be incomplete. Below is a list of supported file types."
msgstr ""
msgid "One or more of your personal access tokens has expired." msgid "One or more of your personal access tokens has expired."
msgstr "" msgstr ""
@ -40677,9 +40632,6 @@ msgstr ""
msgid "ProductAnalytics|Then, return to this page and continue with the setup." msgid "ProductAnalytics|Then, return to this page and continue with the setup."
msgstr "" msgstr ""
msgid "ProductAnalytics|This feature is in Beta and requires purchasing a quota of events, which you receive on each billing period."
msgstr ""
msgid "ProductAnalytics|This group has no projects with product analytics onboarded in the current period." msgid "ProductAnalytics|This group has no projects with product analytics onboarded in the current period."
msgstr "" msgstr ""
@ -47716,6 +47668,9 @@ msgstr ""
msgid "Security dashboard" msgid "Security dashboard"
msgstr "" msgstr ""
msgid "Security policy bot cannot be added as a group member"
msgstr ""
msgid "Security policy project is already assigned." msgid "Security policy project is already assigned."
msgstr "" msgstr ""
@ -50886,6 +50841,9 @@ msgstr ""
msgid "Some common domains are not allowed. %{learn_more_link}." msgid "Some common domains are not allowed. %{learn_more_link}."
msgstr "" msgstr ""
msgid "Some files cannot be displayed due to their file path encoding."
msgstr ""
msgid "Some friendly information" msgid "Some friendly information"
msgstr "" msgstr ""
@ -58856,9 +58814,6 @@ msgstr ""
msgid "View it on GitLab" msgid "View it on GitLab"
msgstr "" msgstr ""
msgid "View job"
msgstr ""
msgid "View job currently using resource" msgid "View job currently using resource"
msgstr "" msgstr ""

View File

@ -1,4 +1,4 @@
ARG GDK_SHA=969c5a7300f11c715d717519db10296279942e27 ARG GDK_SHA=b960aa9662ef68666030a046536f09a232d1602b
# Use tag prefix when running on 'stable' branch to make sure 'protected' image is used which is not deleted by registry cleanup # Use tag prefix when running on 'stable' branch to make sure 'protected' image is used which is not deleted by registry cleanup
ARG GDK_BASE_TAG_PREFIX ARG GDK_BASE_TAG_PREFIX

View File

@ -1,14 +1,17 @@
# frozen_string_literal: true # frozen_string_literal: true
require "spec_helper" require "spec_helper"
RSpec.describe Pajamas::CardComponent, :aggregate_failures, type: :component do RSpec.describe Pajamas::CardComponent, :aggregate_failures, type: :component, feature_category: :design_system do
let(:header) { 'Card header' } let(:header) { 'Slot header' }
let(:body) { 'Card body' } let(:body) { 'Slot body' }
let(:footer) { 'Card footer' } let(:footer) { 'Slot footer' }
context 'for slots' do
let(:card) { {} }
context 'slots' do
before do before do
render_inline described_class.new do |c| render_inline described_class.new(card: card) do |c|
c.with_header { header } c.with_header { header }
c.with_body { body } c.with_body { body }
c.with_footer { footer } c.with_footer { footer }
@ -26,6 +29,25 @@ RSpec.describe Pajamas::CardComponent, :aggregate_failures, type: :component do
it 'renders footer' do it 'renders footer' do
expect(page).to have_content(footer) expect(page).to have_content(footer)
end end
context 'when both slots and card is supplied slot will override' do
let(:card) { { header: 'Card header', body: 'Card body', footer: 'Card footer' } }
it 'renders card header' do
expect(page).to have_content(header)
expect(page).not_to have_content(card[:header])
end
it 'renders card body' do
expect(page).to have_content(body)
expect(page).not_to have_content(card[:body])
end
it 'renders footer' do
expect(page).to have_content(footer)
expect(page).not_to have_content(card[:footer])
end
end
end end
context 'with defaults' do context 'with defaults' do
@ -77,4 +99,29 @@ RSpec.describe Pajamas::CardComponent, :aggregate_failures, type: :component do
expect(page).to have_selector('[data-testid="_footer_testid_"]') expect(page).to have_selector('[data-testid="_footer_testid_"]')
end end
end end
context 'with collection' do
let(:first_card) { { header: 'First card header', body: 'Card body', footer: 'Card footer' } }
let(:second_card) { { body: 'Second card body' } }
before do
render_inline described_class.with_collection([first_card, second_card])
end
it 'renders 2 cards' do
expect(page).to have_selector('.gl-card', count: 2)
end
it 'renders all elements for first card' do
expect(page).to have_content(first_card[:header])
expect(page).to have_content(first_card[:body])
expect(page).to have_content(first_card[:footer])
end
it 'renders only body for second card' do
expect(page).to have_selector('.gl-card-header', count: 1)
expect(page).to have_content(second_card[:body])
expect(page).to have_selector('.gl-card-footer', count: 1)
end
end
end end

View File

@ -1,6 +1,20 @@
# frozen_string_literal: true # frozen_string_literal: true
module Pajamas module Pajamas
class CardComponentPreview < ViewComponent::Preview class CardComponentPreview < ViewComponent::Preview
COLLECTION = [
{
header: 'header',
body: 'Every card has a body',
footer: 'footer'
},
{
header: 'second header',
body: 'second body',
footer: 'second footer'
}
].freeze
# Card # Card
# ---- # ----
# See its design reference [here](https://design.gitlab.com/components/card). # See its design reference [here](https://design.gitlab.com/components/card).
@ -10,18 +24,19 @@ module Pajamas
# @param footer text # @param footer text
def default(header: nil, body: "Every card has a body.", footer: nil) def default(header: nil, body: "Every card has a body.", footer: nil)
render(Pajamas::CardComponent.new) do |c| render(Pajamas::CardComponent.new) do |c|
if header c.with_header { header } if header
c.with_header { header }
end
c.with_body do c.with_body do
content_tag(:p, body) content_tag(:p, body)
end end
if footer c.with_footer { footer } if footer
c.with_footer { footer }
end end
end end
# @param collection [Array] "collection of cards as an array of hashes with header, body, footer"
def with_collection(collection: COLLECTION)
render(Pajamas::CardComponent.with_collection(collection, card_options: { class: 'gl-mb-5' }))
end end
end end
end end

View File

@ -27,11 +27,34 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag
end end
describe "GET show" do describe "GET show" do
let(:params) { { namespace_id: project.namespace, project_id: project, id: id, ref_type: ref_type } }
let(:ref_type) { nil }
let(:request) do
get(:show, params: params)
end
render_views render_views
context 'with file path' do context 'with file path' do
include_context 'with ambiguous refs for controllers'
before do before do
get :show, params: { namespace_id: project.namespace, project_id: project, id: id } request
end
context 'when the ref is ambiguous' do
let(:ref) { 'ambiguous_ref' }
let(:ref_type) { 'tags' }
let(:path) { 'README.md' }
let(:id) { "#{ref}/#{path}" }
it_behaves_like '#set_is_ambiguous_ref when ref is ambiguous'
end
describe '#set_is_ambiguous_ref with no ambiguous ref' do
let(:id) { 'master/README.md' }
it_behaves_like '#set_is_ambiguous_ref when ref is not ambiguous'
end end
context "valid branch, valid file" do context "valid branch, valid file" do
@ -173,6 +196,7 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag
end end
end end
describe 'loading tags' do
it 'loads tags for commits' do it 'loads tags for commits' do
expect_next_instance_of(CommitCollection) do |collection| expect_next_instance_of(CommitCollection) do |collection|
expect(collection).to receive(:load_tags) expect(collection).to receive(:load_tags)
@ -182,6 +206,7 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
end end
end
context 'when tag has a non-ASCII encoding' do context 'when tag has a non-ASCII encoding' do
before do before do

View File

@ -108,22 +108,6 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d
end end
end end
context 'when enable_environments_search_within_folder FF is disabled' do
before do
stub_feature_flags(enable_environments_search_within_folder: false)
end
it 'ignores name inside folder' do
create(:environment, project: project, name: 'review-app', state: :available)
get :index, params: environment_params(format: :json, search: 'review')
expect(environments.map { |env| env['name'] }).to contain_exactly('review-app')
expect(json_response['available_count']).to eq 1
expect(json_response['stopped_count']).to eq 0
end
end
it 'sets the polling interval header' do it 'sets the polling interval header' do
subject subject

View File

@ -265,12 +265,6 @@ RSpec.describe SessionsController, feature_category: :system_access do
end end
context 'when new_broadcast_message_dismissal feature flag is enabled' do context 'when new_broadcast_message_dismissal feature flag is enabled' do
def expect_logging_cookie_creat(message)
expect(Gitlab::AppLogger).to have_received(:info).with(a_string_starting_with(
"Creating cookie for broadcast message dismissal: user_id=#{user.id} broadcast_message_id=#{message.id}"
))
end
before do before do
allow(Gitlab::AppLogger).to receive(:info).and_call_original allow(Gitlab::AppLogger).to receive(:info).and_call_original
stub_feature_flags(new_broadcast_message_dismissal: true) stub_feature_flags(new_broadcast_message_dismissal: true)
@ -286,8 +280,6 @@ RSpec.describe SessionsController, feature_category: :system_access do
expect(cookies["hide_broadcast_message_#{message_banner.id}"]).to be(true) expect(cookies["hide_broadcast_message_#{message_banner.id}"]).to be(true)
expect(cookies["hide_broadcast_message_#{message_notification.id}"]).to be(true) expect(cookies["hide_broadcast_message_#{message_notification.id}"]).to be(true)
expect(cookies["hide_broadcast_message_#{other_message.id}"]).to be_nil expect(cookies["hide_broadcast_message_#{other_message.id}"]).to be_nil
expect_logging_cookie_creat(message_banner)
expect_logging_cookie_creat(message_notification)
end end
context 'when dismissal is expired' do context 'when dismissal is expired' do

View File

@ -21,13 +21,13 @@ RSpec.describe 'Database schema', feature_category: :database do
ci_pipeline_artifacts: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient ci_pipeline_artifacts: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_sources_projects: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient ci_sources_projects: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_daily_build_group_report_results: [%w[partition_id last_pipeline_id]], # index on last_pipeline_id is sufficient ci_daily_build_group_report_results: [%w[partition_id last_pipeline_id]], # index on last_pipeline_id is sufficient
ci_builds: [%w[partition_id stage_id], %w[partition_id execution_config_id], %w[auto_canceled_by_partition_id auto_canceled_by_id], %w[partition_id commit_id]], # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142804#note_1745483081 ci_builds: [%w[partition_id stage_id], %w[partition_id execution_config_id], %w[auto_canceled_by_partition_id auto_canceled_by_id], %w[upstream_pipeline_partition_id upstream_pipeline_id], %w[partition_id commit_id]], # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142804#note_1745483081
ci_pipeline_variables: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient ci_pipeline_variables: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
p_ci_pipeline_variables: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient p_ci_pipeline_variables: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_pipelines_config: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient ci_pipelines_config: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_pipeline_metadata: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient ci_pipeline_metadata: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_pipeline_messages: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient ci_pipeline_messages: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
p_ci_builds: [%w[partition_id stage_id], %w[partition_id execution_config_id], %w[auto_canceled_by_partition_id auto_canceled_by_id], %w[partition_id commit_id]], # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142804#note_1745483081 p_ci_builds: [%w[partition_id stage_id], %w[partition_id execution_config_id], %w[auto_canceled_by_partition_id auto_canceled_by_id], %w[upstream_pipeline_partition_id upstream_pipeline_id], %w[partition_id commit_id]], # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142804#note_1745483081
ci_stages: [%w[partition_id pipeline_id]], # the index on pipeline_id is sufficient ci_stages: [%w[partition_id pipeline_id]], # the index on pipeline_id is sufficient
p_ci_stages: [%w[partition_id pipeline_id]], # the index on pipeline_id is sufficient p_ci_stages: [%w[partition_id pipeline_id]], # the index on pipeline_id is sufficient
ai_testing_terms_acceptances: %w[user_id], # testing terms only have 1 entry, and if the user is deleted the record should remain ai_testing_terms_acceptances: %w[user_id], # testing terms only have 1 entry, and if the user is deleted the record should remain

View File

@ -64,18 +64,6 @@ RSpec.describe Environments::EnvironmentsFinder do
expect(result).to contain_exactly(environment_available_b) expect(result).to contain_exactly(environment_available_b)
end end
context 'when enable_environments_search_within_folder FF is disabled' do
before do
stub_feature_flags(enable_environments_search_within_folder: false)
end
it 'ignores name inside folder' do
result = described_class.new(project, user, search: 'folder', states: :available).execute
expect(result).to be_empty
end
end
end end
context 'with id' do context 'with id' do

View File

@ -19,7 +19,7 @@ RSpec.describe Users::BroadcastMessageDismissalFinder, '#execute', feature_categ
create(:broadcast_message_dismissal, broadcast_message: other_message, user: build(:user)) create(:broadcast_message_dismissal, broadcast_message: other_message, user: build(:user))
end end
subject(:execute) { described_class.new(user, message_ids: message_ids).execute } subject(:execute) { described_class.new(user).execute }
it 'provides valid user dismissals' do it 'provides valid user dismissals' do
expect(execute).to match_array([banner_dismissal, notification_dismissal]) expect(execute).to match_array([banner_dismissal, notification_dismissal])
@ -30,10 +30,6 @@ RSpec.describe Users::BroadcastMessageDismissalFinder, '#execute', feature_categ
create(:broadcast_message_dismissal, :expired, user: user) create(:broadcast_message_dismissal, :expired, user: user)
end end
let(:message_ids) do
[message_banner.id, message_notification.id, other_message.id, expired_banner_dismissal.broadcast_message.id]
end
it 'does not include the expired dismissal' do it 'does not include the expired dismissal' do
expect(execute).to match_array([banner_dismissal, notification_dismissal]) expect(execute).to match_array([banner_dismissal, notification_dismissal])
end end

View File

@ -1,7 +1,6 @@
import { buildClient } from '~/observability/client'; import { buildClient } from '~/observability/client';
export function createMockClient() { export const mockApiConfig = {
const mockClient = buildClient({
provisioningUrl: 'provisioning-url', provisioningUrl: 'provisioning-url',
tracingUrl: 'tracing-url', tracingUrl: 'tracing-url',
tracingAnalyticsUrl: 'tracing-analytics-url', tracingAnalyticsUrl: 'tracing-analytics-url',
@ -13,7 +12,10 @@ export function createMockClient() {
logsSearchUrl: 'logs-search-url', logsSearchUrl: 'logs-search-url',
logsSearchMetadataUrl: 'logs-search-metadata-url', logsSearchMetadataUrl: 'logs-search-metadata-url',
analyticsUrl: 'analytics-url', analyticsUrl: 'analytics-url',
}); };
export function createMockClient() {
const mockClient = buildClient(mockApiConfig);
Object.getOwnPropertyNames(mockClient) Object.getOwnPropertyNames(mockClient)
.filter((item) => typeof mockClient[item] === 'function') .filter((item) => typeof mockClient[item] === 'function')

View File

@ -1,6 +1,5 @@
import { GlLink } from '@gitlab/ui'; import { GlLink, GlExperimentBadge } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ExperimentBadge from '~/vue_shared/components/badges/experiment_badge.vue';
import LogViewerTopBar from '~/ci/job_log_viewer/components/log_viewer_top_bar.vue'; import LogViewerTopBar from '~/ci/job_log_viewer/components/log_viewer_top_bar.vue';
@ -15,7 +14,7 @@ describe('LogViewerTopBar', () => {
}); });
}; };
const findExperimentBadge = () => wrapper.findComponent(ExperimentBadge); const findExperimentBadge = () => wrapper.findComponent(GlExperimentBadge);
const findLink = () => wrapper.findComponent(GlLink); const findLink = () => wrapper.findComponent(GlLink);
it('renders help experiment badge with link', () => { it('renders help experiment badge with link', () => {

Some files were not shown because too many files have changed in this diff Show More