diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index 04f16f175c1..8a99fe52329 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -1839,7 +1839,8 @@ ee/app/workers/ai/repository_xray/ /ee/lib/sidebars/ /ee/lib/ee/sidebars/ -^[Foundations::Design System] @gitlab-org/foundations/design-system/engineering +# Necessary to keep the design system in-sync +[Foundations::Design System] @gitlab-org/foundations/design-system/engineering /app/components/pajamas/ # Necessary for availability, similar to DB migrations diff --git a/.gitlab/merge_request_templates/Quarantine End to End Test.md b/.gitlab/merge_request_templates/Quarantine End to End Test.md index f5774167a5a..c4590bda676 100644 --- a/.gitlab/merge_request_templates/Quarantine End to End Test.md +++ b/.gitlab/merge_request_templates/Quarantine End to End Test.md @@ -19,14 +19,14 @@ the noise (due to constantly failing tests, flaky tests, and so on) so that new - [ ] [Code review guidelines](https://docs.gitlab.com/development/code_review/) - [ ] [Style guides](https://docs.gitlab.com/development/contributing/style_guides/) - [ ] Quarantine test check-list - - [ ] Follow the [Quarantining Tests guide](https://handbook.gitlab.com/handbook/engineering/infrastructure/test-platform/pipeline-triage/#quarantining-tests). - - [ ] Confirm the test has a [`quarantine:` tag with the specified quarantine type](https://handbook.gitlab.com/handbook/engineering/infrastructure/test-platform/pipeline-triage/#quarantined-test-types). + - [ ] Follow the [Quarantining Tests guide](https://handbook.gitlab.com/handbook/engineering/infrastructure-platforms/developer-experience/pipeline-triage/#quarantining-tests). + - [ ] Confirm the test has a [`quarantine:` tag with the specified quarantine type](https://handbook.gitlab.com/handbook/engineering/infrastructure-platforms/developer-experience/pipeline-triage/#quarantined-test-types). - [ ] Note if the test should be [quarantined for a specific environment](https://docs.gitlab.com/development/testing_guide/end_to_end/execution_context_selection/#quarantine-a-test-for-a-specific-environment). - [ ] (Optionally) In case of an emergency (e.g. blocked deployments), consider adding labels to pick into auto-deploy (~"Pick into auto-deploy" ~"priority::1" ~"severity::1"). - [ ] Dequarantine test check-list - - [ ] Follow the [Dequarantining Tests guide](https://handbook.gitlab.com/handbook/engineering/infrastructure/test-platform/pipeline-triage/#dequarantining-tests). + - [ ] Follow the [Dequarantining Tests guide](https://handbook.gitlab.com/handbook/engineering/infrastructure-platforms/developer-experience/pipeline-triage/#dequarantining-tests). - [ ] Confirm the test consistently passes on the target GitLab environment(s). -- [ ] To ensure a faster turnaround, ask in the `#quality_maintainers` Slack channel for someone to review and merge the merge request, rather than assigning it directly. +- [ ] To ensure a faster turnaround, ask in the `#dx_maintainers` Slack channel for someone to review and merge the merge request, rather than assigning it directly. /label ~"Quality" ~"QA" ~"type::maintenance" ~"maintenance::pipelines" diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 5d11faeacf9..26b7518b054 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -153,18 +153,34 @@ class GroupsController < Groups::ApplicationController def merge_requests; end def update - if Groups::UpdateService.new(@group, current_user, group_params).execute + update_result = Groups::UpdateService.new(@group, current_user, group_params).execute - if @group.namespace_settings.errors.present? - flash[:alert] = group.namespace_settings.errors.full_messages.to_sentence + respond_to do |format| + if update_result + format.html do + if @group.namespace_settings.errors.present? + flash[:alert] = @group.namespace_settings.errors.full_messages.to_sentence + else + flash[:notice] = "Group '#{@group.name}' was successfully updated." + end + + redirect_to edit_group_origin_location + end + + format.json do + head :no_content + end else - flash[:notice] = "Group '#{@group.name}' was successfully updated." - end + format.html do + @group.reset - redirect_to edit_group_origin_location - else - @group.reset - render action: "edit" + render action: 'edit' + end + + format.json do + render json: {}, status: :unprocessable_entity + end + end end end diff --git a/app/models/users/group_callout.rb b/app/models/users/group_callout.rb index 01a3792b6d2..c3f1ce3a420 100644 --- a/app/models/users/group_callout.rb +++ b/app/models/users/group_callout.rb @@ -37,7 +37,9 @@ module Users expired_duo_pro_trial_widget: 26, # EE-only expired_duo_enterprise_trial_widget: 27, # EE-only expired_trial_status_widget: 28, # EE-only - namespace_user_cap_reached_alert: 29 # EE-only + namespace_user_cap_reached_alert: 29, # EE-only, + enable_duo_banner_duo_settings_page: 30, ## EE-only + enable_duo_banner_group_page: 31 # EE-only } validates :group, presence: true diff --git a/app/views/groups/_home_panel.html.haml b/app/views/groups/_home_panel.html.haml index 9183bda63d8..14dfeb6050b 100644 --- a/app/views/groups/_home_panel.html.haml +++ b/app/views/groups/_home_panel.html.haml @@ -3,6 +3,13 @@ - emails_disabled = @group.emails_disabled? .group-home-panel + + - unless @group.subgroup? + = render_if_exists 'groups/enable_duo_banner', + title: s_('AiPowered|AI-native features now available in IDEs'), + group: @group, + callouts_feature_name: 'enable_duo_banner_group_page' + .gl-flex.gl-justify-between.gl-flex-wrap.gl-flex-col.sm:gl-flex-row.gl-gap-3.gl-my-5 .home-panel-title-row.gl-flex = render Pajamas::AvatarComponent.new(@group, alt: @group.name, size: 48, class: 'float-none gl-self-start gl-shrink-0 gl-mr-3', avatar_options: { itemprop: 'logo' }) diff --git a/doc/user/application_security/vulnerabilities/validity_check.md b/doc/user/application_security/vulnerabilities/validity_check.md new file mode 100644 index 00000000000..dda631b2839 --- /dev/null +++ b/doc/user/application_security/vulnerabilities/validity_check.md @@ -0,0 +1,77 @@ +--- +stage: Application Security Testing +group: Secret Detection +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments +title: Validity checks +--- + +{{< details >}} + +Status: Experiment + +- Tier: Ultimate +- Offering: GitLab.com, GitLab Dedicated + +{{< /details >}} + +{{< history >}} + +- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/520923) in GitLab 18.0 [with a flag](../../../api/feature_flags.md) named `validity_checks`. Disabled by default. + +{{< /history >}} + +{{< alert type="flag" >}} + +The availability of this feature is controlled by a feature flag. +For more information, see the history. +This feature is available for testing, but not ready for production use. + +{{< /alert >}} + +## What is a validity check? + +GitLab validity checks determines whether a secret, like an access token, is active. + +A secret is active when: + +- It is not expired. +- It can be used for authentication. + +Because active secrets can be used to impersonate a legitimate user, they pose a +greater security risk than inactive secrets. If several secrets are leaked at once, +knowing which secrets are active is an important part of triage and remediation. + +This feature is an [experiment](../../../policy/development_stages_support.md). + +## Enable validity checks + +Prerequisites: + +- You must have a project with pipeline security scanning enabled. + +To enable validity checks for a project: + +- Contact your GitLab representative and ask them to enable validity checks. + +If validity checks are enabled, when the `secret_detection` CI/CD job is complete, +GitLab checks the status of supported detected secrets. The statuses are displayed on the +**Findings** page of the vulnerability report. + +## Coverage + +Validity checks supports the following secret types: + +- GitLab personal access tokens +- Routable GitLab personal access tokens + +## Secret status + +A secret has one of the following statuses: + +- **Possibly active** - GitLab couldn't verify the secret status, or the secret type is not supported by validity checks. +- **Active** - The secret is not expired and can be used for authentication. +- **Inactive** - The secret is expired or revoked and cannot be used for authentication. + +You should rotate **Active** and **Possibly active** detected secrets as soon as possible. +If a secret has an unexpected status, run a new pipeline and wait for the `secret_detection` +job to finish. diff --git a/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml index fe89a93967e..a6f0a66d9ad 100644 --- a/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml @@ -270,7 +270,7 @@ dependency-scanning: ADDITIONAL_SUPPORTED_FILES: "pom.xml,build.gradle,build.gradle.kts,build.sbt,requirements.pip,Pipfile,requires.txt,setup.py" stage: !reference [.ds-analyzer, stage] image: - name: "$CI_TEMPLATE_REGISTRY_HOST/security-products/dependency-scanning:v0" + name: "$SECURE_ANALYZERS_PREFIX/security-products/dependency-scanning:v0" script: - /analyzer run allow_failure: true @@ -360,7 +360,7 @@ dependency-scanning-with-reachability: ADDITIONAL_SUPPORTED_FILES: "pom.xml,build.gradle,build.gradle.kts,build.sbt,requirements.pip,Pipfile,requires.txt,setup.py" SCA_TO_SARIF_MATCHER_VERSION: "v2.0.2" image: - name: "$CI_TEMPLATE_REGISTRY_HOST/security-products/dependency-scanning:v0" + name: "$SECURE_ANALYZERS_PREFIX/dependency-scanning:v0" needs: - job: gitlab-static-reachability optional: true diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 4fe9cf116a6..57a96a5e1e4 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -5705,6 +5705,9 @@ msgstr "" msgid "AiImpactAnalytics|Value can't be calculated due to insufficient data." msgstr "" +msgid "AiPowered|AI-native features now available in IDEs" +msgstr "" + msgid "AiPowered|Always off" msgstr "" @@ -5729,6 +5732,9 @@ msgstr "" msgid "AiPowered|Change configuration" msgstr "" +msgid "AiPowered|Code Suggestions and Chat are now available in supported IDEs as part of GitLab Duo Core for all users of your %{plan} plan." +msgstr "" + msgid "AiPowered|Configuration" msgstr "" @@ -5759,6 +5765,9 @@ msgstr "" msgid "AiPowered|Enable AI logs" msgstr "" +msgid "AiPowered|Enable GitLab Duo Core" +msgstr "" + msgid "AiPowered|Enabled" msgstr "" @@ -5792,12 +5801,18 @@ msgstr "" msgid "AiPowered|Features are not available. However, any group, subgroup, or project can turn them on." msgstr "" +msgid "AiPowered|Get started with GitLab Duo Core" +msgstr "" + msgid "AiPowered|GitLab Duo Chat conversation expiration" msgstr "" msgid "AiPowered|GitLab Duo Core available to all users" msgstr "" +msgid "AiPowered|GitLab Duo Core will be available to all users in your %{plan} plan, including Chat and Code Suggestions in supported IDEs. %{eligibilityLinkStart}Eligibility requirements apply%{eligibilityLinkEnd}. By enabling GitLab Duo, you accept the %{aiLinkStart}GitLab AI functionality terms%{aiLinkEnd}." +msgstr "" + msgid "AiPowered|GitLab Duo Pro or Enterprise" msgstr "" @@ -5819,6 +5834,9 @@ msgstr "" msgid "AiPowered|Indirect connections through GitLab self-managed instance" msgstr "" +msgid "AiPowered|Learn more" +msgstr "" + msgid "AiPowered|Local AI Gateway URL" msgstr "" @@ -27758,6 +27776,9 @@ msgstr "" msgid "GitLab Duo Chat with Amazon Q" msgstr "" +msgid "GitLab Duo Core is now enabled." +msgstr "" + msgid "GitLab Duo Pro seats" msgstr "" diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index fb4830659d8..ec4c0a33d75 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -855,6 +855,26 @@ RSpec.describe GroupsController, :with_current_organization, factory_default: :k expect(response).to have_gitlab_http_status(:ok) end end + + context 'when request is JSON format' do + subject do + put :update, params: { id: group.to_param, group: { path: 'new_path' } }, format: :json + end + + context 'when update service returns false' do + before do + allow_next_instance_of(::Groups::UpdateService) do |instance| + allow(instance).to receive(:execute).and_return(false) + end + end + + it 'responds with :unprocess_entity' do + subject + + expect(response).to have_gitlab_http_status(:unprocessable_entity) + end + end + end end context "updating :resource_access_token_creation_allowed" do diff --git a/spec/support/shared_examples/lib/gitlab/template/ast_templates_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/template/ast_templates_shared_examples.rb index a8a66e631a0..c19126b9db1 100644 --- a/spec/support/shared_examples/lib/gitlab/template/ast_templates_shared_examples.rb +++ b/spec/support/shared_examples/lib/gitlab/template/ast_templates_shared_examples.rb @@ -104,6 +104,30 @@ RSpec.shared_examples 'has expected jobs' do |jobs| end end +RSpec.shared_examples 'has expected image tag' do |tag, jobs| + jobs.each do |job| + it "uses image tag #{tag} for job #{job}" do + build = pipeline.builds.find_by(name: job) + image_tag = expand_job_image(build).rpartition(':').last + expect(image_tag).to eql(tag) + end + end +end + +RSpec.shared_examples 'uses SECURE_ANALYZERS_PREFIX' do |jobs| + context 'when SECURE_ANALYZERS_PREFIX is set', fips_mode: false do + include_context 'with CI variables', { 'SECURE_ANALYZERS_PREFIX' => 'my.custom-registry' } + + jobs.each do |job| + it "uses SECURE_ANALYZERS_PREFIX for the image of job #{job}" do + build = pipeline.builds.find_by(name: job) + image_without_tag = expand_job_image(build).rpartition(':').first + expect(image_without_tag).to start_with('my.custom-registry') + end + end + end +end + RSpec.shared_examples 'has FIPS compatible jobs' do |variable, jobs| context 'when CI_GITLAB_FIPS_MODE=false', fips_mode: false do jobs.each do |job| @@ -157,3 +181,8 @@ RSpec.shared_examples 'acts as branch pipeline' do |jobs| end end end + +def expand_job_image(build) + variables = build.variables.sort_and_expand_all + ExpandVariables.expand(build.image.name, variables) +end