diff --git a/app/assets/javascripts/releases/components/app_edit_new.vue b/app/assets/javascripts/releases/components/app_edit_new.vue index 3080dd0e424..1a07e0ed762 100644 --- a/app/assets/javascripts/releases/components/app_edit_new.vue +++ b/app/assets/javascripts/releases/components/app_edit_new.vue @@ -6,7 +6,6 @@ import MarkdownField from '~/vue_shared/components/markdown/field.vue'; import { BACK_URL_PARAM } from '~/releases/constants'; import { getParameterByName } from '~/lib/utils/common_utils'; import AssetLinksForm from './asset_links_form.vue'; -import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import MilestoneCombobox from '~/milestones/project_milestone_combobox.vue'; import TagField from './tag_field.vue'; @@ -22,7 +21,6 @@ export default { MilestoneCombobox, TagField, }, - mixins: [glFeatureFlagsMixin()], computed: { ...mapState('detail', [ 'isFetchingRelease', @@ -68,9 +66,6 @@ export default { cancelPath() { return getParameterByName(BACK_URL_PARAM) || this.releasesPagePath; }, - showAssetLinksForm() { - return this.glFeatures.releaseAssetLinkEditing; - }, saveButtonLabel() { return this.isExistingRelease ? __('Save changes') : __('Create release'); }, @@ -176,7 +171,7 @@ export default { - +
+import { GlButton } from '@gitlab/ui'; import statusIcon from '../mr_widget_status_icon.vue'; export default { name: 'MRWidgetArchived', components: { + GlButton, statusIcon, }, }; @@ -12,9 +14,9 @@ export default {
- +
diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb index 0c98af0d487..698510a5323 100644 --- a/app/controllers/projects/releases_controller.rb +++ b/app/controllers/projects/releases_controller.rb @@ -7,7 +7,6 @@ class Projects::ReleasesController < Projects::ApplicationController before_action :authorize_read_release! before_action do push_frontend_feature_flag(:release_evidence_collection, project, default_enabled: true) - push_frontend_feature_flag(:release_asset_link_editing, project, default_enabled: true) push_frontend_feature_flag(:graphql_release_data, project, default_enabled: true) push_frontend_feature_flag(:graphql_milestone_stats, project, default_enabled: true) push_frontend_feature_flag(:graphql_releases_page, project, default_enabled: true) diff --git a/app/models/deploy_token.rb b/app/models/deploy_token.rb index 395260b5201..9355d73fae9 100644 --- a/app/models/deploy_token.rb +++ b/app/models/deploy_token.rb @@ -78,6 +78,20 @@ class DeployToken < ApplicationRecord end end + def group + strong_memoize(:group) do + groups.first + end + end + + def accessible_projects + if project_type? + projects + elsif group_type? + group.all_projects + end + end + def holder strong_memoize(:holder) do if project_type? diff --git a/app/models/project.rb b/app/models/project.rb index 47a5514111d..456f177f32b 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -604,7 +604,7 @@ class Project < ApplicationRecord return public_to_user unless user if user.is_a?(DeployToken) - user.projects + user.accessible_projects else where('EXISTS (?) OR projects.visibility_level IN (?)', user.authorizations_for_projects(min_access_level: min_access_level), diff --git a/app/services/projects/container_repository/cleanup_tags_service.rb b/app/services/projects/container_repository/cleanup_tags_service.rb index 31500043544..b8047a1ad71 100644 --- a/app/services/projects/container_repository/cleanup_tags_service.rb +++ b/app/services/projects/container_repository/cleanup_tags_service.rb @@ -4,7 +4,6 @@ module Projects module ContainerRepository class CleanupTagsService < BaseService def execute(container_repository) - return error('feature disabled') unless can_use? return error('access denied') unless can_destroy? return error('invalid regex') unless valid_regex? @@ -74,10 +73,6 @@ module Projects can?(current_user, :destroy_container_image, project) end - def can_use? - Feature.enabled?(:container_registry_cleanup, project, default_enabled: true) - end - def valid_regex? %w(name_regex_delete name_regex name_regex_keep).each do |param_name| regex = params[param_name] diff --git a/changelogs/unreleased/235822-maven-group-token.yml b/changelogs/unreleased/235822-maven-group-token.yml new file mode 100644 index 00000000000..4ad0bbc8fa2 --- /dev/null +++ b/changelogs/unreleased/235822-maven-group-token.yml @@ -0,0 +1,6 @@ +--- +title: Fix group deploy tokens to return all projects and work with the Maven group + endpoint +merge_request: 43628 +author: +type: fixed diff --git a/config/feature_flags/development/container_registry_cleanup.yml b/config/feature_flags/development/container_registry_cleanup.yml deleted file mode 100644 index a03f530b339..00000000000 --- a/config/feature_flags/development/container_registry_cleanup.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -name: container_registry_cleanup -introduced_by_url: -rollout_issue_url: -group: -type: development -default_enabled: true diff --git a/config/feature_flags/development/epics_search.yml b/config/feature_flags/development/epics_search.yml deleted file mode 100644 index 00ad45e300f..00000000000 --- a/config/feature_flags/development/epics_search.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -name: epics_search -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42456 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/250317 -group: group::global search -type: development -default_enabled: false \ No newline at end of file diff --git a/config/feature_flags/development/json_limited_encoder.yml b/config/feature_flags/development/json_limited_encoder.yml index 3afed64b4cc..d20b5412233 100644 --- a/config/feature_flags/development/json_limited_encoder.yml +++ b/config/feature_flags/development/json_limited_encoder.yml @@ -1,7 +1,7 @@ --- name: json_limited_encoder -introduced_by_url: -rollout_issue_url: -group: +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38687 +rollout_issue_url: +group: group::source code type: development default_enabled: false diff --git a/doc/integration/jira_development_panel.md b/doc/integration/jira_development_panel.md index e91b024546e..6c355ec31c5 100644 --- a/doc/integration/jira_development_panel.md +++ b/doc/integration/jira_development_panel.md @@ -184,6 +184,16 @@ The message `Successfully connected` indicates a successful TLS handshake. If there are problems, the Java TLS library generates errors that you can look up for more detail. +##### Scope error when connecting Jira via DVCS + +```plaintext +The requested scope is invalid, unknown, or malformed. +``` + +Potential resolutions: + +- Verify the URL includes `scope=api` on the end of the URL. + ##### Jira error adding account and no repositories listed ```plaintext diff --git a/doc/user/application_security/secret_detection/index.md b/doc/user/application_security/secret_detection/index.md index aea9b91d9f2..4cc5bd020f3 100644 --- a/doc/user/application_security/secret_detection/index.md +++ b/doc/user/application_security/secret_detection/index.md @@ -38,7 +38,7 @@ To run Secret Detection jobs, by default, you need GitLab Runner with the If you're using the shared runners on GitLab.com, this is enabled by default. CAUTION: **Caution:** -Our Secret Detection jobs currently expect a Linux container type. Windows containers are not yet supported. +Our Secret Detection jobs expect a Linux container type. Windows containers are not supported. CAUTION: **Caution:** If you use your own runners, make sure the Docker version installed @@ -139,7 +139,7 @@ Secret Detection can be customized by defining available variables: |-------------------------|---------------|-------------| | `SECRET_DETECTION_COMMIT_FROM` | - | The commit a Gitleaks scan starts at. | | `SECRET_DETECTION_COMMIT_TO` | - | The commit a Gitleaks scan ends at. | -| `SECRET_DETECTION_EXCLUDED_PATHS` | "" | Exclude vulnerabilities from output based on the paths. This is a comma-separated list of patterns. Patterns can be globs, or file or folder paths (for example, `doc,spec` ). Parent directories will also match patterns. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225273) in GitLab 13.3. | +| `SECRET_DETECTION_EXCLUDED_PATHS` | "" | Exclude vulnerabilities from output based on the paths. This is a comma-separated list of patterns. Patterns can be globs, or file or folder paths (for example, `doc,spec` ). Parent directories also match patterns. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225273) in GitLab 13.3. | | `SECRET_DETECTION_HISTORIC_SCAN` | false | Flag to enable a historic Gitleaks scan. | ### Logging level diff --git a/doc/user/search/index.md b/doc/user/search/index.md index cf9bf61c868..aa99455e1cf 100644 --- a/doc/user/search/index.md +++ b/doc/user/search/index.md @@ -223,6 +223,7 @@ backed by the database and allows searching in: - Merge requests - Milestones - Users +- Epics (Group only) - Code (Project only) - Comments (Project only) - Commits (Project only) diff --git a/spec/frontend/releases/components/app_edit_new_spec.js b/spec/frontend/releases/components/app_edit_new_spec.js index 3367ca8ba3a..d92bdc3b99a 100644 --- a/spec/frontend/releases/components/app_edit_new_spec.js +++ b/spec/frontend/releases/components/app_edit_new_spec.js @@ -20,7 +20,7 @@ describe('Release edit/new component', () => { let state; let mock; - const factory = ({ featureFlags = {}, store: storeUpdates = {} } = {}) => { + const factory = async ({ featureFlags = {}, store: storeUpdates = {} } = {}) => { state = { release, markdownDocsPath: 'path/to/markdown/docs', @@ -68,6 +68,8 @@ describe('Release edit/new component', () => { }, }); + await wrapper.vm.$nextTick(); + wrapper.element.querySelectorAll('input').forEach(input => jest.spyOn(input, 'focus')); }; @@ -89,7 +91,9 @@ describe('Release edit/new component', () => { const findForm = () => wrapper.find('form'); describe(`basic functionality tests: all tests unrelated to the "${BACK_URL_PARAM}" parameter`, () => { - beforeEach(factory); + beforeEach(async () => { + await factory(); + }); it('calls initializeRelease when the component is created', () => { expect(actions.initializeRelease).toHaveBeenCalledTimes(1); @@ -131,7 +135,9 @@ describe('Release edit/new component', () => { }); describe(`when the URL does not contain a "${BACK_URL_PARAM}" parameter`, () => { - beforeEach(factory); + beforeEach(async () => { + await factory(); + }); it(`renders a "Cancel" button with an href pointing to "${BACK_URL_PARAM}"`, () => { const cancelButton = wrapper.find('.js-cancel-button'); @@ -142,12 +148,12 @@ describe('Release edit/new component', () => { describe(`when the URL contains a "${BACK_URL_PARAM}" parameter`, () => { const backUrl = 'https://example.gitlab.com/back/url'; - beforeEach(() => { + beforeEach(async () => { commonUtils.getParameterByName = jest .fn() .mockImplementation(paramToGet => ({ [BACK_URL_PARAM]: backUrl }[paramToGet])); - factory(); + await factory(); }); it('renders a "Cancel" button with an href pointing to the main Releases page', () => { @@ -157,8 +163,8 @@ describe('Release edit/new component', () => { }); describe('when creating a new release', () => { - beforeEach(() => { - factory({ + beforeEach(async () => { + await factory({ store: { modules: { detail: { @@ -177,7 +183,9 @@ describe('Release edit/new component', () => { }); describe('when editing an existing release', () => { - beforeEach(factory); + beforeEach(async () => { + await factory(); + }); it('renders the submit button with the text "Save changes"', () => { expect(findSubmitButton().text()).toBe('Save changes'); @@ -185,33 +193,17 @@ describe('Release edit/new component', () => { }); describe('asset links form', () => { - const findAssetLinksForm = () => wrapper.find(AssetLinksForm); + beforeEach(factory); - describe('when the release_asset_link_editing feature flag is disabled', () => { - beforeEach(() => { - factory({ featureFlags: { releaseAssetLinkEditing: false } }); - }); - - it('does not render the asset links portion of the form', () => { - expect(findAssetLinksForm().exists()).toBe(false); - }); - }); - - describe('when the release_asset_link_editing feature flag is enabled', () => { - beforeEach(() => { - factory({ featureFlags: { releaseAssetLinkEditing: true } }); - }); - - it('renders the asset links portion of the form', () => { - expect(findAssetLinksForm().exists()).toBe(true); - }); + it('renders the asset links portion of the form', () => { + expect(wrapper.find(AssetLinksForm).exists()).toBe(true); }); }); describe('validation', () => { describe('when the form is valid', () => { - beforeEach(() => { - factory({ + beforeEach(async () => { + await factory({ store: { modules: { detail: { @@ -230,8 +222,8 @@ describe('Release edit/new component', () => { }); describe('when the form is invalid', () => { - beforeEach(() => { - factory({ + beforeEach(async () => { + await factory({ store: { modules: { detail: { diff --git a/spec/models/deploy_token_spec.rb b/spec/models/deploy_token_spec.rb index 9fd3751be13..60a3e3fc0e2 100644 --- a/spec/models/deploy_token_spec.rb +++ b/spec/models/deploy_token_spec.rb @@ -353,4 +353,29 @@ RSpec.describe DeployToken do end end end + + describe '#accessible_projects' do + subject { deploy_token.accessible_projects } + + context 'when a deploy token is associated to a project' do + let_it_be(:deploy_token) { create(:deploy_token, :project) } + + it 'returns only projects directly associated with the token' do + expect(deploy_token).to receive(:projects) + + subject + end + end + + context 'when a deploy token is associated to a group' do + let_it_be(:group) { create(:group) } + let_it_be(:deploy_token) { create(:deploy_token, :group, groups: [group]) } + + it 'returns all projects from the group' do + expect(group).to receive(:all_projects) + + subject + end + end + end end diff --git a/spec/requests/api/maven_packages_spec.rb b/spec/requests/api/maven_packages_spec.rb index a67bc157e5a..8580c0ab4d4 100644 --- a/spec/requests/api/maven_packages_spec.rb +++ b/spec/requests/api/maven_packages_spec.rb @@ -15,10 +15,13 @@ RSpec.describe API::MavenPackages do let_it_be(:job, reload: true) { create(:ci_build, user: user, status: :running) } let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) } let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) } + let_it_be(:deploy_token_for_group) { create(:deploy_token, :group, read_package_registry: true, write_package_registry: true) } + let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: deploy_token_for_group, group: group) } let(:workhorse_token) { JWT.encode({ 'iss' => 'gitlab-workhorse' }, Gitlab::Workhorse.secret, 'HS256') } let(:headers) { { 'GitLab-Workhorse' => '1.0', Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER => workhorse_token } } let(:headers_with_token) { headers.merge('Private-Token' => personal_access_token.token) } + let(:group_deploy_token_headers) { { Gitlab::Auth::AuthFinders::DEPLOY_TOKEN_HEADER => deploy_token_for_group.token } } let(:headers_with_deploy_token) do headers.merge( @@ -342,6 +345,17 @@ RSpec.describe API::MavenPackages do it_behaves_like 'downloads with a job token' it_behaves_like 'downloads with a deploy token' + + context 'with group deploy token' do + subject { download_file_with_token(package_file.file_name, {}, group_deploy_token_headers) } + + it 'returns the file' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response.media_type).to eq('application/octet-stream') + end + end end def download_file(file_name, params = {}, request_headers = headers) diff --git a/spec/services/projects/container_repository/cleanup_tags_service_spec.rb b/spec/services/projects/container_repository/cleanup_tags_service_spec.rb index 2f2474f2681..8ddcb8ce660 100644 --- a/spec/services/projects/container_repository/cleanup_tags_service_spec.rb +++ b/spec/services/projects/container_repository/cleanup_tags_service_spec.rb @@ -12,8 +12,6 @@ RSpec.describe Projects::ContainerRepository::CleanupTagsService do before do project.add_maintainer(user) - stub_feature_flags(container_registry_cleanup: true) - stub_container_registry_config(enabled: true) stub_container_registry_tags(