diff options
20 files changed, 112 insertions, 54 deletions
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index c5e6c021e93..8f160c2ce4f 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -82,6 +82,9 @@ .if-merge-request-labels-pipeline-revert: &if-merge-request-labels-pipeline-revert if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:revert/' +.if-merge-request-labels-frontend-and-feature-flag: &if-merge-request-labels-frontend-and-feature-flag + if: '$CI_MERGE_REQUEST_LABELS =~ /frontend/ && $CI_MERGE_REQUEST_LABELS =~ /feature flag/' + .if-security-merge-request: &if-security-merge-request if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security" && $CI_MERGE_REQUEST_IID' @@ -845,6 +848,7 @@ - <<: *if-fork-merge-request when: never - <<: *if-merge-request-labels-run-all-jest + - <<: *if-merge-request-labels-frontend-and-feature-flag - <<: *if-merge-request changes: [".gitlab/ci/rules.gitlab-ci.yml", ".gitlab/ci/frontend.gitlab-ci.yml"] - <<: *if-automated-merge-request @@ -861,10 +865,10 @@ - !reference [".frontend:rules:minimal-default-rules", rules] - <<: *if-merge-request-labels-run-all-jest when: never - - changes: *core-frontend-patterns + - <<: *if-merge-request-labels-frontend-and-feature-flag when: never - <<: *if-merge-request - changes: *ci-patterns + changes: [".gitlab/ci/rules.gitlab-ci.yml", ".gitlab/ci/frontend.gitlab-ci.yml"] when: never - <<: *if-merge-request changes: *code-backstage-patterns diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 3f3cedde315..1a2cb3681bc 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -1751c8d22d795af285d2d850fe8fa71dc6dbc80d +e1dd9bfe694190e9350dad37b5cd8b5ea44eafa3 diff --git a/app/assets/stylesheets/_page_specific_files.scss b/app/assets/stylesheets/_page_specific_files.scss index 4a9a79e3b07..65d27aad4a2 100644 --- a/app/assets/stylesheets/_page_specific_files.scss +++ b/app/assets/stylesheets/_page_specific_files.scss @@ -1,4 +1,3 @@ -@import './pages/branches'; @import './pages/colors'; @import './pages/commits'; @import './pages/detail_page'; diff --git a/app/assets/stylesheets/pages/branches.scss b/app/assets/stylesheets/page_bundles/branches.scss index 18158fab75f..2aa90529e22 100644 --- a/app/assets/stylesheets/pages/branches.scss +++ b/app/assets/stylesheets/page_bundles/branches.scss @@ -1,3 +1,5 @@ +@import 'mixins_and_variables_and_functions'; + .branch-info { flex: auto; min-width: 0; diff --git a/app/policies/packages/policies/project_policy.rb b/app/policies/packages/policies/project_policy.rb index c754d24349a..0fb5953f2aa 100644 --- a/app/policies/packages/policies/project_policy.rb +++ b/app/policies/packages/policies/project_policy.rb @@ -52,3 +52,5 @@ module Packages end end end + +Packages::Policies::ProjectPolicy.prepend_mod_with('Packages::Policies::ProjectPolicy') diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml index 295b2de9bd2..df01900dd1b 100644 --- a/app/views/projects/branches/index.html.haml +++ b/app/views/projects/branches/index.html.haml @@ -1,3 +1,4 @@ +- add_page_specific_style 'page_bundles/branches' - page_title _('Branches') - add_to_breadcrumbs(_('Repository'), project_tree_path(@project)) diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml index 23572d1d6ac..6e202063900 100644 --- a/app/views/projects/commit/_commit_box.html.haml +++ b/app/views/projects/commit/_commit_box.html.haml @@ -30,7 +30,7 @@ = preserve(markdown_field(@commit, :description)) .info-well.js-commit-box-info{ 'data-commit-path' => branches_project_commit_path(@project, @commit.id) } - .well-segment.branch-info + .well-segment .icon-container.commit-icon = custom_icon("icon_commit") %span.cgray= n_('parent', 'parents', @commit.parents.count) diff --git a/app/views/projects/pipelines/_info.html.haml b/app/views/projects/pipelines/_info.html.haml index 2e403358e2e..6f56aea7bd2 100644 --- a/app/views/projects/pipelines/_info.html.haml +++ b/app/views/projects/pipelines/_info.html.haml @@ -45,7 +45,7 @@ - if @pipeline.stuck? = gl_badge_tag s_('Pipelines|stuck'), { variant: :warning, size: :sm }, { class: 'js-pipeline-url-stuck has-tooltip' } - .well-segment.branch-info + .well-segment .icon-container.commit-icon = sprite_icon('commit', css_class: 'gl-top-0!') = link_to commit.short_id, project_commit_path(@project, @pipeline.sha), class: "commit-sha" diff --git a/config/application.rb b/config/application.rb index 9a2ba12e127..c0030e92961 100644 --- a/config/application.rb +++ b/config/application.rb @@ -262,6 +262,7 @@ module Gitlab config.assets.precompile << "page_bundles/alert_management_settings.css" config.assets.precompile << "page_bundles/billings.css" config.assets.precompile << "page_bundles/boards.css" + config.assets.precompile << "page_bundles/branches.css" config.assets.precompile << "page_bundles/build.css" config.assets.precompile << "page_bundles/ci_status.css" config.assets.precompile << "page_bundles/cluster_agents.css" diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md index c52b3b5adae..0350171544d 100644 --- a/doc/development/documentation/index.md +++ b/doc/development/documentation/index.md @@ -181,32 +181,30 @@ To prepare an update to the `CODEOWNERS` file: bundle exec rake tw:codeowners > ~/Desktop/updates.md ``` -1. Open the file you just created (`~/Desktop/updates.md` in this example), and prepare the output: - - Find and replace `./` with `/`. - - Sort the lines in alphabetical (ascending) order. If you use VS Code, you can - select everything, press <kbd>F1</kbd>, type `sort`, and select **Sort lines (ascending, case insensitive**. -1. Create a new branch for your `CODEOWNERS` updates. -1. Replace the documentation-related lines in the `^[Documentation Pages]` section - with the output you prepared. - - WARNING: - The documentation section is not the last section of the `CODEOWNERS` file. Don't - delete data that isn't ours! - -1. Create a commit with the raw changes. -1. From the command line, run `git diff master`. -1. In the diff, look for directory-level assignments to manually restore to the - `CODEOWNERS` file. If all files in a single directory are assigned to the same - technical writer, we simplify these entries. Remove all the lines for the individual - files, and leave a single entry for the directory, for example: `/doc/directory/ @tech.writer`. -1. In the diff, look for changes that don't match your expectations: +1. Open the file you just created (`~/Desktop/updates.md` in this example). Check + that the lines are in alphabetical (ascending) order. If you have to sort + the lines and you use VS Code, you can select everything, press <kbd>F1</kbd>, + type `sort`, and select **Sort lines (ascending, case insensitive)**. +1. In the output, look for changes that don't match your expectations: - New pages, or newly moved pages, show up as added lines. - Deleted pages, and pages that are now redirects, show up as deleted lines. - If you see an unusual number of changes to pages that all seem related, check the metadata for the pages. A group might have been renamed and the Rake task must be updated to match. -1. Create another commit with your manual changes, and create a second merge request - with your changes to the `CODEOWNERS` file. Assign it to a technical writing manager for review. + - If all files in a single directory are assigned to the same + technical writer, simplify these entries. Remove all the lines for the individual + files, and leave a single entry for the directory, for example: `/doc/directory/ @tech.writer`. +1. When you are happy with the output, create a new branch to update the + [`CODEOWNERS`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/CODEOWNERS) + file. Replace the documentation-related lines in the `^[Documentation Pages]` + section with the output you prepared. + + WARNING: + The documentation section is not the last section of the `CODEOWNERS` file. Don't + delete data that isn't ours! + +1. Create a merge request from this branch with your changes to the `CODEOWNERS` file. + Assign it to a technical writing manager for review. ## Move, rename, or delete a page diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md index ce1ba5f2dc9..a5dc7a727d8 100644 --- a/doc/development/documentation/styleguide/word_list.md +++ b/doc/development/documentation/styleguide/word_list.md @@ -77,9 +77,9 @@ Instead of: - The documentation is written by contributors. NOTE: -If you can add the phrase "by zombies" to the end of the sentence, +If you can add the phrase "by zombies" to the phrase, the construction is passive. For example, `The button is selected by zombies` -is passive. `Select the button` is active. +is passive. `Zombies select the button` is active. ## administrator diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md index 00d9588d087..779010b8aa1 100644 --- a/doc/development/fe_guide/vue.md +++ b/doc/development/fe_guide/vue.md @@ -65,6 +65,9 @@ To do that, you can use the `data` attributes in the HTML element and query them You should only do this while initializing the application, because the mounted element is replaced with a Vue-generated DOM. +The `data` attributes are [only able to accept String values](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes#javascript_access), +so you will need to cast or convert other variable types to String. + The advantage of providing data from the DOM to the Vue instance through `props` or `provide` in the `render` function, instead of querying the DOM inside the main Vue component, is that you avoid creating a fixture or an HTML element in the unit test. diff --git a/doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md b/doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md index 930a9bb7e59..8a041b08a4d 100644 --- a/doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md +++ b/doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md @@ -101,13 +101,12 @@ or manually with Google Cloud Shell: 1. After the Cloud Shell starts, run these commands to install NGINX Ingress Controller: ```shell - kubectl create ns gitlab-managed-apps - helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx - helm repo update - helm install ingress ngress-nginx/ingress-nginx -n gitlab-managed-apps + helm upgrade --install ingress-nginx ingress-nginx \ + --repo https://kubernetes.github.io/ingress-nginx \ + --namespace gitlab-managed-apps --create-namespace # Check that the ingress controller is installed successfully - kubectl get service ingress-nginx-ingress-controller -n gitlab-managed-apps + kubectl get service ingress-nginx-controller -n gitlab-managed-apps ``` ## Configure Auto DevOps @@ -118,7 +117,7 @@ Follow these steps to configure the base domain and other settings required for get the external IP address with the following command: ```shell - kubectl get service ingress-nginx-ingress-controller -n gitlab-managed-apps -ojson | jq -r '.status.loadBalancer.ingress[].ip' + kubectl get service ingress-nginx-controller -n gitlab-managed-apps -ojson | jq -r '.status.loadBalancer.ingress[].ip' ``` Replace `gitlab-managed-apps` if you have overwritten your namespace. diff --git a/doc/topics/release_your_application.md b/doc/topics/release_your_application.md index 6f1c7bb4a40..851396f9bf3 100644 --- a/doc/topics/release_your_application.md +++ b/doc/topics/release_your_application.md @@ -28,7 +28,7 @@ deployment using GitLab CI/CD. With the extensive integration between GitLab and Kubernetes, you can safely deploy your applications to Kubernetes clusters using the [GitLab agent](../user/clusters/agent/install/index.md). -#### GitOps deployments **(PREMIUM)** +#### GitOps deployments With the [GitLab agent for Kubernetes](../user/clusters/agent/install/index.md), you can perform [pull-based deployments of Kubernetes manifests](../user/clusters/agent/gitops.md). This provides a scalable, secure, diff --git a/doc/user/free_user_limit.md b/doc/user/free_user_limit.md index 3fbfb2e1aa7..74885b8ff2e 100644 --- a/doc/user/free_user_limit.md +++ b/doc/user/free_user_limit.md @@ -29,6 +29,34 @@ If you need more time to manage your members, or to try GitLab features with a team of more than five members, you can [start a trial](https://gitlab.com/-/trial_registrations/new?glm_source=docs.gitlab.com&glm_content=free-user-limit). A trial lasts for 30 days and includes an unlimited number of members. +## Determining namespace user counts + +Every unique user of a top-level namespace with private visibility counts towards the five-user limit. This includes every user of a group, subgroup, and project within a namespace. + +For example: + +The group `example-1` has: + +- One group owner, `A`. +- One subgroup called `subgroup-1` with one member, `B`. + - `subgroup-1` inherits `A` as a member from `example-1`. +- One project in `subgroup-1` called `project-1` with two members, `C` and `D`. + - `project-1` inherits `A` and `B` as members from `subgroup-1`. + +The namespace `example-1` has four unique members: `A`, `B`, `C`, and `D`. Because `example-1` has only four unique members, it is not impacted by the five-user limit. + +The group `example-2` has: + +- One group owner, `A`. +- One subgroup called `subgroup-2` with one member, `B`. + - `subgroup-2` inherits `A` as a member from `example-2`. +- One project in `subgroup-2` called `project-2a` with two members, `C` and `D`. + - `project-2a` inherits `A` and `B` as members from `subgroup-2`. +- One project in `subgroup-2` called `project-2b` with two members, `E` and `F`. + - `project-2b` inherits `A` and `B` as members from `subgroup-2`. + +The namespace `example-2` has six unique members: `A`, `B`, `C`, `D`, `E`, and `F`. Because `example-2` has six unique users, it is impacted by the five-user limit. + ## Related topics - [GitLab SaaS Free tier frequently asked questions](https://about.gitlab.com/pricing/faq-efficient-free-tier/) diff --git a/lib/api/members.rb b/lib/api/members.rb index faa2ff45441..f4e38207aca 100644 --- a/lib/api/members.rb +++ b/lib/api/members.rb @@ -104,7 +104,7 @@ module API end params do requires :access_level, type: Integer, desc: 'A valid access level (defaults: `30`, developer access level)' - requires :user_id, types: Array[Integer], coerce_with: Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'The user ID of the new member or multiple IDs separated by commas.' + requires :user_id, types: [Integer, String], desc: 'The user ID of the new member or multiple IDs separated by commas.' optional :expires_at, type: DateTime, desc: 'Date string in the format YEAR-MONTH-DAY' optional :invite_source, type: String, desc: 'Source that triggered the member creation process', default: 'members-api' optional :tasks_to_be_done, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Tasks the inviter wants the member to do' diff --git a/lib/api/pypi_packages.rb b/lib/api/pypi_packages.rb index 1f27fcce879..a2386411524 100644 --- a/lib/api/pypi_packages.rb +++ b/lib/api/pypi_packages.rb @@ -95,9 +95,9 @@ module API find_authorized_group! end - def ensure_project! + def project!(action: :read_package) find_project(params[:id]) || not_found! - authorized_user_project + authorized_user_project(action: action) end end @@ -161,10 +161,6 @@ module API end resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do - before do - ensure_project! - end - namespace ':id/packages/pypi' do desc 'The PyPi package download endpoint' do detail 'This feature was introduced in GitLab 12.10' @@ -176,8 +172,7 @@ module API route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth get 'files/:sha256/*file_identifier' do - project = authorized_user_project - authorize_read_package!(project) + project = project! filename = "#{params[:file_identifier]}.#{params[:format]}" package = Packages::Pypi::PackageFinder.new(current_user, project, { filename: filename, sha256: params[:sha256] }).execute @@ -196,7 +191,7 @@ module API # PyPi simple API returns a list of packages as a simple HTML file. route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth get 'simple', format: :txt do - present_simple_index(authorized_user_project) + present_simple_index(project!) end desc 'The PyPi Simple Project Package Endpoint' do @@ -211,7 +206,7 @@ module API # PyPi simple API returns the package descriptor as a simple HTML file. route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth get 'simple/*package_name', format: :txt do - present_simple_package(authorized_user_project) + present_simple_package(project!) end desc 'The PyPi Package upload endpoint' do @@ -229,15 +224,16 @@ module API route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth post do - authorize_upload!(authorized_user_project) - bad_request!('File is too large') if authorized_user_project.actual_limits.exceeded?(:pypi_max_file_size, params[:content].size) + project = project!(action: :read_project) + authorize_upload!(project) + bad_request!('File is too large') if project.actual_limits.exceeded?(:pypi_max_file_size, params[:content].size) - track_package_event('push_package', :pypi, project: authorized_user_project, user: current_user, namespace: authorized_user_project.namespace) + track_package_event('push_package', :pypi, project: project, user: current_user, namespace: project.namespace) unprocessable_entity! if Gitlab::FIPS.enabled? && declared_params[:md5_digest].present? ::Packages::Pypi::CreatePackageService - .new(authorized_user_project, current_user, declared_params.merge(build: current_authenticated_job)) + .new(project, current_user, declared_params.merge(build: current_authenticated_job)) .execute created! @@ -249,10 +245,11 @@ module API route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth post 'authorize' do + project = project!(action: :read_project) authorize_workhorse!( - subject: authorized_user_project, + subject: project, has_length: false, - maximum_size: authorized_user_project.actual_limits.pypi_max_file_size + maximum_size: project.actual_limits.pypi_max_file_size ) end end diff --git a/lib/tasks/gitlab/tw/codeowners.rake b/lib/tasks/gitlab/tw/codeowners.rake index 19337f50f1b..4dc129949c4 100644 --- a/lib/tasks/gitlab/tw/codeowners.rake +++ b/lib/tasks/gitlab/tw/codeowners.rake @@ -66,7 +66,7 @@ namespace :tw do CodeOwnerRule.new('Redirect', 'Redirect'), CodeOwnerRule.new('Release', '@rdickenson'), CodeOwnerRule.new('Respond', '@msedlakjakubowski'), - CodeOwnerRule.new('Runner', '@sselhorn'), + CodeOwnerRule.new('Runner', '@fneill'), CodeOwnerRule.new('Pods', '@jglassman1'), CodeOwnerRule.new('Security Policies', '@claytoncornell'), CodeOwnerRule.new('Source Code', '@aqualls'), diff --git a/spec/requests/api/pypi_packages_spec.rb b/spec/requests/api/pypi_packages_spec.rb index 6c130bb4963..12091158a02 100644 --- a/spec/requests/api/pypi_packages_spec.rb +++ b/spec/requests/api/pypi_packages_spec.rb @@ -69,6 +69,7 @@ RSpec.describe API::PypiPackages do it_behaves_like 'rejects PyPI access with unknown project id' it_behaves_like 'deploy token for package GET requests' it_behaves_like 'job token for package GET requests' + it_behaves_like 'allow access for everyone with public package_registry_access_level' context 'with project path as id' do let(:url) { "/projects/#{CGI.escape(project.full_path)}/packages/pypi/simple" } @@ -130,6 +131,7 @@ RSpec.describe API::PypiPackages do it_behaves_like 'rejects PyPI access with unknown project id' it_behaves_like 'deploy token for package GET requests' it_behaves_like 'job token for package GET requests' + it_behaves_like 'allow access for everyone with public package_registry_access_level' context 'with project path as id' do let(:url) { "/projects/#{CGI.escape(project.full_path)}/packages/pypi/simple/#{package.name}" } @@ -377,6 +379,7 @@ RSpec.describe API::PypiPackages do it_behaves_like 'pypi file download endpoint' it_behaves_like 'rejects PyPI access with unknown project id' + it_behaves_like 'allow access for everyone with public package_registry_access_level' end end end diff --git a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb index 11e19d8d067..a9b44015206 100644 --- a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb @@ -221,6 +221,27 @@ RSpec.shared_examples 'rejects PyPI access with unknown group id' do end end +RSpec.shared_examples 'allow access for everyone with public package_registry_access_level' do + context 'with private project but public access to package registry' do + before do + project.update_column(:visibility_level, Gitlab::VisibilityLevel::PRIVATE) + project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC) + end + + context 'as non-member user' do + let(:headers) { basic_auth_header(user.username, personal_access_token.token) } + + it_behaves_like 'returning response status', :success + end + + context 'as anonymous' do + let(:headers) { {} } + + it_behaves_like 'returning response status', :success + end + end +end + RSpec.shared_examples 'pypi simple API endpoint' do using RSpec::Parameterized::TableSyntax |