Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-11-04 21:13:55 +00:00
parent fe448fa0fc
commit 2fdc3eaafb
27 changed files with 527 additions and 107 deletions

View File

@ -15,14 +15,14 @@ export default {
...mapGetters('batchComments', ['draftsCount', 'sortedDrafts']),
},
methods: {
...mapActions('diffs', ['toggleActiveFileByHash']),
...mapActions('diffs', ['setCurrentFileHash']),
...mapActions('batchComments', ['scrollToDraft']),
isLast(index) {
return index === this.sortedDrafts.length - 1;
},
async onClickDraft(draft) {
if (this.viewDiffsFileByFile && draft.file_hash) {
await this.toggleActiveFileByHash(draft.file_hash);
await this.setCurrentFileHash(draft.file_hash);
}
await this.scrollToDraft(draft);

View File

@ -221,7 +221,7 @@ export default {
'toggleFileDiscussions',
'toggleFileDiscussionWrappers',
'toggleFullDiff',
'toggleActiveFileByHash',
'setCurrentFileHash',
'reviewFile',
'setFileCollapsedByUser',
]),
@ -244,7 +244,7 @@ export default {
scrollToElement(document.querySelector(selector));
window.location.hash = selector;
if (!this.viewDiffsFileByFile) {
this.toggleActiveFileByHash(this.diffFile.file_hash);
this.setCurrentFileHash(this.diffFile.file_hash);
}
}
},

View File

@ -85,6 +85,12 @@ export const setBaseConfig = ({ commit }, options) => {
viewDiffsFileByFile,
mrReviews,
});
Array.from(new Set(Object.values(mrReviews).flat())).forEach((id) => {
const viewedId = id.replace(/^hash:/, '');
commit(types.SET_DIFF_FILE_VIEWED, { id: viewedId, seen: true });
});
};
export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => {
@ -127,7 +133,7 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => {
}
if (!isNoteLink && !state.currentDiffFileId) {
commit(types.VIEW_DIFF_FILE, diff_files[0]?.file_hash);
commit(types.SET_CURRENT_DIFF_FILE, diff_files[0]?.file_hash);
}
if (isNoteLink) {
@ -143,7 +149,7 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => {
!state.diffFiles.some((f) => f.file_hash === state.currentDiffFileId) &&
!isNoteLink
) {
commit(types.VIEW_DIFF_FILE, state.diffFiles[0].file_hash);
commit(types.SET_CURRENT_DIFF_FILE, state.diffFiles[0].file_hash);
}
if (state.diffFiles?.length) {
@ -248,7 +254,7 @@ export const fetchCoverageFiles = ({ commit, state }) => {
export const setHighlightedRow = ({ commit }, lineCode) => {
const fileHash = lineCode.split('_')[0];
commit(types.SET_HIGHLIGHTED_ROW, lineCode);
commit(types.VIEW_DIFF_FILE, fileHash);
commit(types.SET_CURRENT_DIFF_FILE, fileHash);
handleLocationHash();
};
@ -514,8 +520,8 @@ export const toggleTreeOpen = ({ commit }, path) => {
commit(types.TOGGLE_FOLDER_OPEN, path);
};
export const toggleActiveFileByHash = ({ commit }, hash) => {
commit(types.VIEW_DIFF_FILE, hash);
export const setCurrentFileHash = ({ commit }, hash) => {
commit(types.SET_CURRENT_DIFF_FILE, hash);
};
export const scrollToFile = ({ state, commit, getters }, { path, setHash = true }) => {
@ -523,7 +529,7 @@ export const scrollToFile = ({ state, commit, getters }, { path, setHash = true
const { fileHash } = state.treeEntries[path];
commit(types.VIEW_DIFF_FILE, fileHash);
commit(types.SET_CURRENT_DIFF_FILE, fileHash);
if (getters.isVirtualScrollingEnabled) {
eventHub.$emit('scrollToFileHash', fileHash);
@ -806,7 +812,7 @@ export const setCurrentDiffFileIdFromNote = ({ commit, state, rootGetters }, not
const fileHash = rootGetters.getDiscussion(note.discussion_id).diff_file?.file_hash;
if (fileHash && state.diffFiles.some((f) => f.file_hash === fileHash)) {
commit(types.VIEW_DIFF_FILE, fileHash);
commit(types.SET_CURRENT_DIFF_FILE, fileHash);
}
};
@ -814,7 +820,7 @@ export const navigateToDiffFileIndex = ({ commit, state }, index) => {
const fileHash = state.diffFiles[index].file_hash;
document.location.hash = fileHash;
commit(types.VIEW_DIFF_FILE, fileHash);
commit(types.SET_CURRENT_DIFF_FILE, fileHash);
};
export const setFileByFile = ({ state, commit }, { fileByFile }) => {
@ -850,6 +856,8 @@ export function reviewFile({ commit, state }, { file, reviewed = true }) {
const reviews = markFileReview(state.mrReviews, file, reviewed);
setReviewsForMergeRequest(mrPath, reviews);
commit(types.SET_DIFF_FILE_VIEWED, { id: file.file_hash, seen: reviewed });
commit(types.SET_MR_FILE_REVIEWS, reviews);
}

View File

@ -20,7 +20,8 @@ export const SET_LINE_DISCUSSIONS_FOR_FILE = 'SET_LINE_DISCUSSIONS_FOR_FILE';
export const REMOVE_LINE_DISCUSSIONS_FOR_FILE = 'REMOVE_LINE_DISCUSSIONS_FOR_FILE';
export const TOGGLE_FOLDER_OPEN = 'TOGGLE_FOLDER_OPEN';
export const SET_SHOW_TREE_LIST = 'SET_SHOW_TREE_LIST';
export const VIEW_DIFF_FILE = 'VIEW_DIFF_FILE';
export const SET_CURRENT_DIFF_FILE = 'SET_CURRENT_DIFF_FILE';
export const SET_DIFF_FILE_VIEWED = 'SET_DIFF_FILE_VIEWED';
export const OPEN_DIFF_FILE_COMMENT_FORM = 'OPEN_DIFF_FILE_COMMENT_FORM';
export const UPDATE_DIFF_FILE_COMMENT_FORM = 'UPDATE_DIFF_FILE_COMMENT_FORM';

View File

@ -254,9 +254,11 @@ export default {
[types.SET_SHOW_TREE_LIST](state, showTreeList) {
state.showTreeList = showTreeList;
},
[types.VIEW_DIFF_FILE](state, fileId) {
[types.SET_CURRENT_DIFF_FILE](state, fileId) {
state.currentDiffFileId = fileId;
Vue.set(state.viewedDiffFileIds, fileId, true);
},
[types.SET_DIFF_FILE_VIEWED](state, { id, seen }) {
Vue.set(state.viewedDiffFileIds, id, seen);
},
[types.OPEN_DIFF_FILE_COMMENT_FORM](state, formData) {
state.commentForms.push({

View File

@ -52,8 +52,10 @@ export function markFileReview(reviews, file, reviewed = true) {
if (reviewed) {
fileReviews.add(file.id);
fileReviews.add(`hash:${file.file_hash}`);
} else {
fileReviews.delete(file.id);
fileReviews.delete(`hash:${file.file_hash}`);
}
updatedReviews[file.file_identifier_hash] = Array.from(fileReviews);

View File

@ -0,0 +1,26 @@
---
key_path: redis_hll_counters.ci_templates.p_ci_templates_security_sast_iac_latest_monthly
description: Count of pipelines using the latest SAST IaC template
product_section: sec
product_stage: secure
product_group: "group::static analysis"
product_category: SAST
value_type: number
status: active
milestone: "14.5"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73076
time_frame: 28d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
options:
events:
- p_ci_templates_security_sast_iac_latest

View File

@ -0,0 +1,26 @@
---
key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_security_sast_iac_latest_monthly
description: Count of pipelines with implicit runs using the latest SAST IaC template
product_section: sec
product_stage: secure
product_group: "group::static analysis"
product_category: SAST
value_type: number
status: active
milestone: "14.5"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73076
time_frame: 28d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
options:
events:
- p_ci_templates_implicit_security_sast_iac_latest

View File

@ -0,0 +1,26 @@
---
key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_sast_iac_latest_monthly
description: Count of pipelines using the latest SAST IaC template
product_section: sec
product_stage: secure
product_group: "group::static analysis"
product_category: SAST
value_type: number
status: active
milestone: "14.5"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73074
time_frame: 28d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
options:
events:
- p_ci_templates_jobs_sast_iac_latest

View File

@ -0,0 +1,26 @@
---
key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_jobs_sast_iac_latest_monthly
description: Count of pipelines with implicit runs using the latest SAST IaC template
product_section: sec
product_stage: secure
product_group: "group::static analysis"
product_category: SAST
value_type: number
status: active
milestone: "14.5"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73074
time_frame: 28d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
options:
events:
- p_ci_templates_implicit_jobs_sast_iac_latest

View File

@ -0,0 +1,27 @@
---
data_category: optional
key_path: redis_hll_counters.ci_templates.p_ci_templates_security_sast_iac_latest_weekly
description: Count of pipelines using the latest SAST IaC template
product_section: sec
product_stage: secure
product_group: "group::static analysis"
product_category: SAST
value_type: number
status: active
milestone: "14.5"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73076
time_frame: 7d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
options:
events:
- p_ci_templates_security_sast_iac_latest

View File

@ -0,0 +1,26 @@
---
key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_security_sast_iac_latest_weekly
description: Count of pipelines with implicit runs using the latest SAST IaC template
product_section: sec
product_stage: secure
product_group: "group::static analysis"
product_category: SAST
value_type: number
status: active
milestone: "14.5"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73076
time_frame: 7d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
options:
events:
- p_ci_templates_implicit_security_sast_iac_latest

View File

@ -0,0 +1,26 @@
---
key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_sast_iac_latest_weekly
description: Count of pipelines using the latest SAST IaC template
product_section: sec
product_stage: secure
product_group: "group::static analysis"
product_category: SAST
value_type: number
status: active
milestone: "14.5"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73074
time_frame: 7d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
options:
events:
- p_ci_templates_jobs_sast_iac_latest

View File

@ -0,0 +1,26 @@
---
key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_jobs_sast_iac_latest_weekly
description: Count of pipelines with implicit runs using the latest SAST IaC template
product_section: sec
product_stage: secure
product_group: "group::static analysis"
product_category: SAST
value_type: number
status: active
milestone: "14.5"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73074
time_frame: 7d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
options:
events:
- p_ci_templates_implicit_jobs_sast_iac_latest

View File

@ -139,7 +139,7 @@ The initial iteration will provide a framework to house features under `Namespac
1. **Tier**: Is there any tier functionality that is differentiated by projects and groups?
1. **Documentation**: Is the structure and content of documentation impacted by these changes at all?
1. **Solution proposal**:
- Think big: This analysis provides a great opportunity to zoom out and consider the feature UX as a whole. How could you make this feature lovable based on the new structure, inheritance, and capabilities afforded by `Namespaces`? Is there any UI which doesn't comply with Pajamas?
- Think big: This analysis provides a great opportunity to zoom out and consider the feature UX as a whole. How could you make this feature lovable based on the new structure, inheritance, and capabilities afforded by `Namespaces`? Is there any UI which doesn't comply with Pajamas?
- Start small: What are the product changes that need to be made to assist with the migration?
- Move fast: Prioritise these solution ideas, document in issues, and create a roadmap for implementation.
@ -170,3 +170,7 @@ DRIs:
| Design | Nick Post |
<!-- vale gitlab.Spelling = YES -->
## Related topics
- [Workspaces developer documentation](../../../development/workspaces/index.md)

View File

@ -31,6 +31,8 @@ Below are the runners' settings.
| Default Docker image | `ruby:2.5` | - |
| `privileged` (run [Docker in Docker](https://hub.docker.com/_/docker/)) | `true` | `false` |
These runners share a [distributed cache](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) through use of a Google Cloud Storage (GCS) bucket. Cache contents not updated within the last 14 days are automatically removed through use of an [object lifecycle management policy](https://cloud.google.com/storage/docs/lifecycle).
## Pre-clone script
Build Cloud runners for Linux provide a way to run commands in a CI

View File

@ -9,87 +9,112 @@ description: "Development Guidelines: learn about workspaces when developing Git
# Workspaces
[Read more](../../user/workspace/index.md) about the workspaces initiative.
The [Workspaces initiative](../../user/workspace/index.md) focuses on reaching feature parity between
SaaS and self-managed installations.
## Consolidate Groups and Projects
## Consolidate groups and projects
- [Architecture blueprint](../../architecture/blueprints/consolidating_groups_and_projects/index.md)
Consolidate Groups and Projects is one facet of the workspaces initiative, addressing the feature disparity between
groups and projects.
One facet of the workspaces initiative is to consolidate groups and projects,
addressing the feature disparity between them. Some features, such as epics, are
only available at the group level. Some features, such as issues, are only available
at the project level. Other features, such as milestones, are available to both groups
and projects.
There is feature disparity between groups and projects. Some features only available at group level (for example epics).
Some features only available at project level (for example issues). And some features available at both levels
(for example labels, milestones).
We receive many requests to add features either to the group or project level.
Moving features around to different levels is problematic on multiple levels:
We get more and more requests to get one feature or another added to either group or project level. This takes
engineering time, to just move features around to different levels. This also adds a UX overhead of keeping a mental
model of which features are available at which level.
- It requires engineering time to move the features.
- It requires UX overhead to maintain mental models of feature availability.
- It creates redundant code.
This also creates lots of redundant code. Features get copied from project, to group to instance level with small
nuances between them. This also causes extra maintenance, when something needs to be fixed. The fix is copied to
several locations. This also creates different user experience for the same feature but in the different locations.
When features are copied from one level (project, group, or instance) to another,
the copies often have small, nuanced differences between them. These nuances cause
extra engineering time when fixes are needed, because the fix must be copied to
several locations. These nuances also create different user experiences when the
feature is used in different places.
To solve this we are moving towards consolidating groups and projects into a single entity, namespace. The work on this
solution is split into several phases and is tracked in [epic 6473](https://gitlab.com/groups/gitlab-org/-/epics/6473).
A solution for this problem is to consolidate groups and projects into a single
entity, `namespace`. The work on this solution is split into several phases and
is tracked in [epic 6473](https://gitlab.com/groups/gitlab-org/-/epics/6473).
### Phase 1
Epic tracking [Phase 1](https://gitlab.com/groups/gitlab-org/-/epics/6697)
- [Phase 1 epic](https://gitlab.com/groups/gitlab-org/-/epics/6697).
- **Goals**:
1. Ensure every project receives a corresponding record in the `namespaces`
table with `type='Project'`.
1. For user namespaces, the type changes from `NULL` to `User`.
Goal of Phase 1 is to ensure that every project gets a corresponding record in `namespaces` table with `type='Project'`.
For user namespaces, type changes from `NULL` to `User`.
We should make sure that projects, and the project namespace, are equivalent:
Places where we should make sure project and project namespace go hand in hand:
- **Create project:** use Rails callbacks to ensure a new project namespace is
created for each project. Project namespace records should contain `created_at` and
`updated_at` attributes equal to the project's `created_at`/`updated_at` attributes.
- **Update project:** use the `after_save` callback in Rails to ensure some
attributes are kept in sync between project and project namespaces.
Read [`project#after_save`](https://gitlab.com/gitlab-org/gitlab/blob/6d26634e864d7b748dda0e283eb2477362263bc3/app/models/project.rb#L101-L101)
for more information.
- **Delete project:** use FKs cascade delete or Rails callbacks to ensure when a `Project`
or its `ProjectNamespace` is removed, its corresponding `ProjectNamespace` or `Project`
is also removed.
- **Transfer project to a different group:** make sure that when a project is transferred,
its corresponding project namespace is transferred to the same group.
- **Transfer group:** make sure when transferring a group that all of its sub-projects,
either direct or through descendant groups, have their corresponding project
namespaces transferred correctly as well.
- **Export or import project**
- **Export project** continues to export only the project, and not its project namespace,
in this phase. The project namespace does not contain any specific information
to export at this point. Eventually we want the project namespace to be exported as well.
- **Import project** creates a new project, so the project namespace is created through
Rails `after_save` callback on the project model.
- **Export or import group:** when importing or exporting a `Group`, projects are not
included in the operation. If that feature is changed to include `Project` when its group is
imported or exported, the logic must include their corresponding project namespaces
in the import or export.
- Create project.
- Use Rails callbacks to ensure a new project namespace is created for each project.
- In this case project namespace records should have `created_at`/`updated_at` attributes equal to project's `created_at`/`updated_at` attributes.
- Update Project.
- Use Rails `after_save` callback to ensure some attributes are kept in sync between project and project namespaces,
see [project#after_save](https://gitlab.com/gitlab-org/gitlab/blob/6d26634e864d7b748dda0e283eb2477362263bc3/app/models/project.rb#L101-L101).
- Delete project.
- Use FKs cascade delete or Rails callbacks to ensure when either a `Project` or its `ProjectNamespace` is removed its
corresponding `ProjectNamespace` or `Project` respectively is removed as well.
- Transfer project to a different group.
- Make sure that when a project is transferred, its corresponding project namespace is transferred to the same group.
- Transfer group.
- Make sure when transferring a group that all of its sub projects, either direct or through descendant groups, have their
corresponding project namespaces transferred correctly as well.
- Export/import project.
- Export project would continue to only export the project and not its project namespace in this phase. Project
namespace does not contain any specific information that has to be exported at this point. Eventually we want the
project namespace to be exported as well.
- Import creates a new project, so project namespace is created through Rails `after_save` callback on the project model.
- Export/import group.
- As of this writing, when importing or exporting a `Group`, `Project`s are not included in the operation. If that functionality is changed to include `Project` when its Group is imported/exported, the logic must be sure to include their corresponding project namespaces in the import/export.
After ensuring the above points, we plan to run a DB migration to create a `ProjectNamespace` record for every `Project`.
Project namespace records created during migration should have `created_at`/`updated_at` attributes set to migration
runtime. That means that project namespaces `created_at`/`updated_at` attributes don't match their corresponding
project's `created_at`/`updated_at` attributes. We want the different dates to help audit any of the created project
namespaces, in case we need it. We plan to run the back-filling migration in 14.5 milestone.
After ensuring these points, run a database migration to create a `ProjectNamespace`
record for every `Project`. Project namespace records created during the migration
should have `created_at` and `updated_at` attributes set to the migration runtime.
The project namespaces' `created_at` and `updated_at` attributes would not match
their corresponding project's `created_at` and `updated_at` attributes. We want
the different dates to help audit any of the created project namespaces, in case we need it.
After this work completes, we must migrate data as described in
[Backfill `ProjectNamespace` for every Project](https://gitlab.com/gitlab-org/gitlab/-/issues/337100).
### Phase 2
Epic tracking [Phase 2](https://gitlab.com/groups/gitlab-org/-/epics/6768)
- [Phase 2 epic](https://gitlab.com/groups/gitlab-org/-/epics/6768).
- **Goal**: Make `ProjectNamespace` the front entity to interact with instead of `Project`.
In this phase:
- Communicate the changes company-wide at the engineering level. We want to make
engineers aware of the upcoming changes, even though teams are not expected to
collaborate actively until phase 3.
- Raise awareness to avoid regressions, and conflicting or duplicate work that
can be dealt with before phase 3.
The focus of this phase is to make `ProjectNamespace` the front entity to interact with instead of `Project` .
Problems to solve as part of this phase:
- Routes handling through project namespace rather than project.
- Routes handling through `ProjectNamespace` rather than `Project`.
- Memberships handling.
- Policies handling.
- Import/export.
- Import and export.
- Other interactions between project namespace and project models.
Communicate the changes company wide at the engineers level. We want engineers to be aware of the upcoming changes even
though active collaboration of teams is expected only in phase 3. Raise awareness to avoid regressions, conflicting or duplicate work
that can be taken care of even before phase 3.
### Phase 3
Epic tracking [Phase 3](https://gitlab.com/groups/gitlab-org/-/epics/6585)
- [Phase 3 epic](https://gitlab.com/groups/gitlab-org/-/epics/6585).
- **Goal**: Feature parity between the namespace types.
The focus of this phase is to get feature parity between the namespace types. Phase 3 is when active migration
of features from `Project` to `ProjectNamespace` or directly to `Namespace` happens.
Phase 3 is when the active migration of features from `Project` to `ProjectNamespace`,
or directly to `Namespace`, happens.
## Related topics
- [Consolidating groups and projects](../../architecture/blueprints/consolidating_groups_and_projects/index.md)
architecture documentation
- [Workspace user documentation](../../user/workspace/index.md)

View File

@ -46,3 +46,7 @@ The following provide a preview to the Workspace concept.
![Admin Overview](img/Admin_Settings.png)
![Admin Overview](img/hardware_settings.png)
## Related topics
- [Workspaces developer documentation](../../development/workspaces/index.md)

View File

@ -0,0 +1,34 @@
variables:
# Setting this variable will affect all Security templates
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
SAST_EXCLUDED_PATHS: "spec, test, tests, tmp"
iac-sast:
stage: test
artifacts:
reports:
sast: gl-sast-report.json
rules:
- when: never
# `rules` must be overridden explicitly by each child job
# see https://gitlab.com/gitlab-org/gitlab/-/issues/218444
variables:
SEARCH_MAX_DEPTH: 4
allow_failure: true
script:
- /analyzer run
kics-iac-sast:
extends: iac-sast
image:
name: "$SAST_ANALYZER_IMAGE"
variables:
SAST_ANALYZER_IMAGE_TAG: 0
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/kics:$SAST_ANALYZER_IMAGE_TAG"
rules:
- if: $SAST_DISABLED
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /kics/
when: never
- if: $CI_COMMIT_BRANCH

View File

@ -0,0 +1,2 @@
include:
template: Jobs/SAST-IaC.latest.gitlab-ci.yml

View File

@ -83,6 +83,10 @@
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_sast_iac_latest
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_runner_validation
category: ci_templates
redis_slot: ci_templates
@ -267,6 +271,10 @@
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_sast_iac_latest
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_secret_detection
category: ci_templates
redis_slot: ci_templates
@ -447,6 +455,10 @@
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_sast_iac_latest
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_secret_detection
category: ci_templates
redis_slot: ci_templates
@ -503,6 +515,10 @@
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_sast_iac_latest
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_dast_runner_validation
category: ci_templates
redis_slot: ci_templates

View File

@ -7,7 +7,7 @@ Vue.use(Vuex);
let wrapper;
const toggleActiveFileByHash = jest.fn();
const setCurrentFileHash = jest.fn();
const scrollToDraft = jest.fn();
function factory({ viewDiffsFileByFile = false, draftsCount = 1, sortedDrafts = [] } = {}) {
@ -16,7 +16,7 @@ function factory({ viewDiffsFileByFile = false, draftsCount = 1, sortedDrafts =
diffs: {
namespaced: true,
actions: {
toggleActiveFileByHash,
setCurrentFileHash,
},
state: {
viewDiffsFileByFile,
@ -51,7 +51,7 @@ describe('Batch comments preview dropdown', () => {
await Vue.nextTick();
expect(toggleActiveFileByHash).toHaveBeenCalledWith(expect.anything(), 'hash');
expect(setCurrentFileHash).toHaveBeenCalledWith(expect.anything(), 'hash');
expect(scrollToDraft).toHaveBeenCalledWith(expect.anything(), { id: 1, file_hash: 'hash' });
});

View File

@ -7,7 +7,7 @@ import { mockTracking, triggerEvent } from 'helpers/tracking_helper';
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
import { DIFF_FILE_AUTOMATIC_COLLAPSE, DIFF_FILE_MANUAL_COLLAPSE } from '~/diffs/constants';
import { reviewFile } from '~/diffs/store/actions';
import { SET_MR_FILE_REVIEWS } from '~/diffs/store/mutation_types';
import { SET_DIFF_FILE_VIEWED, SET_MR_FILE_REVIEWS } from '~/diffs/store/mutation_types';
import { diffViewerModes } from '~/ide/constants';
import { scrollToElement } from '~/lib/utils/common_utils';
import { truncateSha } from '~/lib/utils/text_utility';
@ -23,6 +23,7 @@ jest.mock('~/lib/utils/common_utils');
const diffFile = Object.freeze(
Object.assign(diffDiscussionsMockData.diff_file, {
id: '123',
file_hash: 'xyz',
file_identifier_hash: 'abc',
edit_path: 'link:/to/edit/path',
blob: {
@ -58,7 +59,7 @@ describe('DiffFileHeader component', () => {
toggleFileDiscussions: jest.fn(),
toggleFileDiscussionWrappers: jest.fn(),
toggleFullDiff: jest.fn(),
toggleActiveFileByHash: jest.fn(),
setCurrentFileHash: jest.fn(),
setFileCollapsedByUser: jest.fn(),
reviewFile: jest.fn(),
},
@ -553,7 +554,13 @@ describe('DiffFileHeader component', () => {
reviewFile,
{ file, reviewed: true },
{},
[{ type: SET_MR_FILE_REVIEWS, payload: { [file.file_identifier_hash]: [file.id] } }],
[
{ type: SET_DIFF_FILE_VIEWED, payload: { id: file.file_hash, seen: true } },
{
type: SET_MR_FILE_REVIEWS,
payload: { [file.file_identifier_hash]: [file.id, `hash:${file.file_hash}`] },
},
],
[],
);
});

View File

@ -99,6 +99,10 @@ describe('DiffsStoreActions', () => {
const projectPath = '/root/project';
const dismissEndpoint = '/-/user_callouts';
const showSuggestPopover = false;
const mrReviews = {
a: ['z', 'hash:a'],
b: ['y', 'hash:a'],
};
testAction(
setBaseConfig,
@ -110,6 +114,7 @@ describe('DiffsStoreActions', () => {
projectPath,
dismissEndpoint,
showSuggestPopover,
mrReviews,
},
{
endpoint: '',
@ -131,8 +136,21 @@ describe('DiffsStoreActions', () => {
projectPath,
dismissEndpoint,
showSuggestPopover,
mrReviews,
},
},
{
type: types.SET_DIFF_FILE_VIEWED,
payload: { id: 'z', seen: true },
},
{
type: types.SET_DIFF_FILE_VIEWED,
payload: { id: 'a', seen: true },
},
{
type: types.SET_DIFF_FILE_VIEWED,
payload: { id: 'y', seen: true },
},
],
[],
done,
@ -190,10 +208,10 @@ describe('DiffsStoreActions', () => {
{ type: types.SET_RETRIEVING_BATCHES, payload: true },
{ type: types.SET_DIFF_DATA_BATCH, payload: { diff_files: res1.diff_files } },
{ type: types.SET_BATCH_LOADING_STATE, payload: 'loaded' },
{ type: types.VIEW_DIFF_FILE, payload: 'test' },
{ type: types.SET_CURRENT_DIFF_FILE, payload: 'test' },
{ type: types.SET_DIFF_DATA_BATCH, payload: { diff_files: res2.diff_files } },
{ type: types.SET_BATCH_LOADING_STATE, payload: 'loaded' },
{ type: types.VIEW_DIFF_FILE, payload: 'test2' },
{ type: types.SET_CURRENT_DIFF_FILE, payload: 'test2' },
{ type: types.SET_RETRIEVING_BATCHES, payload: false },
{ type: types.SET_BATCH_LOADING_STATE, payload: 'error' },
],
@ -307,7 +325,7 @@ describe('DiffsStoreActions', () => {
it('should mark currently selected diff and set lineHash and fileHash of highlightedRow', () => {
testAction(setHighlightedRow, 'ABC_123', {}, [
{ type: types.SET_HIGHLIGHTED_ROW, payload: 'ABC_123' },
{ type: types.VIEW_DIFF_FILE, payload: 'ABC' },
{ type: types.SET_CURRENT_DIFF_FILE, payload: 'ABC' },
]);
});
});
@ -895,7 +913,7 @@ describe('DiffsStoreActions', () => {
expect(document.location.hash).toBe('#test');
});
it('commits VIEW_DIFF_FILE', () => {
it('commits SET_CURRENT_DIFF_FILE', () => {
const state = {
treeEntries: {
path: {
@ -906,7 +924,7 @@ describe('DiffsStoreActions', () => {
scrollToFile({ state, commit, getters }, { path: 'path' });
expect(commit).toHaveBeenCalledWith(types.VIEW_DIFF_FILE, 'test');
expect(commit).toHaveBeenCalledWith(types.SET_CURRENT_DIFF_FILE, 'test');
});
});
@ -1428,7 +1446,7 @@ describe('DiffsStoreActions', () => {
});
describe('setCurrentDiffFileIdFromNote', () => {
it('commits VIEW_DIFF_FILE', () => {
it('commits SET_CURRENT_DIFF_FILE', () => {
const commit = jest.fn();
const state = { diffFiles: [{ file_hash: '123' }] };
const rootGetters = {
@ -1438,10 +1456,10 @@ describe('DiffsStoreActions', () => {
setCurrentDiffFileIdFromNote({ commit, state, rootGetters }, '1');
expect(commit).toHaveBeenCalledWith(types.VIEW_DIFF_FILE, '123');
expect(commit).toHaveBeenCalledWith(types.SET_CURRENT_DIFF_FILE, '123');
});
it('does not commit VIEW_DIFF_FILE when discussion has no diff_file', () => {
it('does not commit SET_CURRENT_DIFF_FILE when discussion has no diff_file', () => {
const commit = jest.fn();
const state = { diffFiles: [{ file_hash: '123' }] };
const rootGetters = {
@ -1454,7 +1472,7 @@ describe('DiffsStoreActions', () => {
expect(commit).not.toHaveBeenCalled();
});
it('does not commit VIEW_DIFF_FILE when diff file does not exist', () => {
it('does not commit SET_CURRENT_DIFF_FILE when diff file does not exist', () => {
const commit = jest.fn();
const state = { diffFiles: [{ file_hash: '123' }] };
const rootGetters = {
@ -1469,12 +1487,12 @@ describe('DiffsStoreActions', () => {
});
describe('navigateToDiffFileIndex', () => {
it('commits VIEW_DIFF_FILE', (done) => {
it('commits SET_CURRENT_DIFF_FILE', (done) => {
testAction(
navigateToDiffFileIndex,
0,
{ diffFiles: [{ file_hash: '123' }] },
[{ type: types.VIEW_DIFF_FILE, payload: '123' }],
[{ type: types.SET_CURRENT_DIFF_FILE, payload: '123' }],
[],
done,
);
@ -1523,13 +1541,14 @@ describe('DiffsStoreActions', () => {
describe('reviewFile', () => {
const file = {
id: '123',
file_hash: 'xyz',
file_identifier_hash: 'abc',
load_collapsed_diff_url: 'gitlab-org/gitlab-test/-/merge_requests/1/diffs',
};
it.each`
reviews | diffFile | reviewed
${{ abc: ['123'] }} | ${file} | ${true}
${{}} | ${file} | ${false}
reviews | diffFile | reviewed
${{ abc: ['123', 'hash:xyz'] }} | ${file} | ${true}
${{}} | ${file} | ${false}
`(
'sets reviews ($reviews) to localStorage and state for file $file if it is marked reviewed=$reviewed',
({ reviews, diffFile, reviewed }) => {

View File

@ -633,16 +633,36 @@ describe('DiffsStoreMutations', () => {
});
});
describe('VIEW_DIFF_FILE', () => {
describe('SET_CURRENT_DIFF_FILE', () => {
it('updates currentDiffFileId', () => {
const state = createState();
mutations[types.VIEW_DIFF_FILE](state, 'somefileid');
mutations[types.SET_CURRENT_DIFF_FILE](state, 'somefileid');
expect(state.currentDiffFileId).toBe('somefileid');
});
});
describe('SET_DIFF_FILE_VIEWED', () => {
let state;
beforeEach(() => {
state = {
viewedDiffFileIds: { 123: true },
};
});
it.each`
id | bool | outcome
${'abc'} | ${true} | ${{ 123: true, abc: true }}
${'123'} | ${false} | ${{ 123: false }}
`('sets the viewed files list to $bool for the id $id', ({ id, bool, outcome }) => {
mutations[types.SET_DIFF_FILE_VIEWED](state, { id, seen: bool });
expect(state.viewedDiffFileIds).toEqual(outcome);
});
});
describe('Set highlighted row', () => {
it('sets highlighted row', () => {
const state = createState();

View File

@ -11,14 +11,14 @@ import {
function getDefaultReviews() {
return {
abc: ['123', '098'],
abc: ['123', 'hash:xyz', '098', 'hash:uvw'],
};
}
describe('File Review(s) utilities', () => {
const mrPath = 'my/fake/mr/42';
const storageKey = `${mrPath}-file-reviews`;
const file = { id: '123', file_identifier_hash: 'abc' };
const file = { id: '123', file_hash: 'xyz', file_identifier_hash: 'abc' };
const storedValue = JSON.stringify(getDefaultReviews());
let reviews;
@ -44,14 +44,14 @@ describe('File Review(s) utilities', () => {
});
describe('reviewStatuses', () => {
const file1 = { id: '123', file_identifier_hash: 'abc' };
const file2 = { id: '098', file_identifier_hash: 'abc' };
const file1 = { id: '123', hash: 'xyz', file_identifier_hash: 'abc' };
const file2 = { id: '098', hash: 'uvw', file_identifier_hash: 'abc' };
it.each`
mrReviews | files | fileReviews
${{}} | ${[file1, file2]} | ${{ 123: false, '098': false }}
${{ abc: ['123'] }} | ${[file1, file2]} | ${{ 123: true, '098': false }}
${{ abc: ['098'] }} | ${[file1, file2]} | ${{ 123: false, '098': true }}
${{ abc: ['123', 'hash:xyz'] }} | ${[file1, file2]} | ${{ 123: true, '098': false }}
${{ abc: ['098', 'hash:uvw'] }} | ${[file1, file2]} | ${{ 123: false, '098': true }}
${{ def: ['123'] }} | ${[file1, file2]} | ${{ 123: false, '098': false }}
${{ abc: ['123'], def: ['098'] }} | ${[]} | ${{}}
`(
@ -128,7 +128,7 @@ describe('File Review(s) utilities', () => {
describe('markFileReview', () => {
it("adds a review when there's nothing that already exists", () => {
expect(markFileReview(null, file)).toStrictEqual({ abc: ['123'] });
expect(markFileReview(null, file)).toStrictEqual({ abc: ['123', 'hash:xyz'] });
});
it("overwrites an existing review if it's for the same file (identifier hash)", () => {
@ -136,15 +136,15 @@ describe('File Review(s) utilities', () => {
});
it('removes a review from the list when `reviewed` is `false`', () => {
expect(markFileReview(reviews, file, false)).toStrictEqual({ abc: ['098'] });
expect(markFileReview(reviews, file, false)).toStrictEqual({ abc: ['098', 'hash:uvw'] });
});
it('adds a new review if the file ID is new', () => {
const updatedFile = { ...file, id: '098' };
const allReviews = markFileReview({ abc: ['123'] }, updatedFile);
const updatedFile = { ...file, id: '098', file_hash: 'uvw' };
const allReviews = markFileReview({ abc: ['123', 'hash:xyz'] }, updatedFile);
expect(allReviews).toStrictEqual(getDefaultReviews());
expect(allReviews.abc).toStrictEqual(['123', '098']);
expect(allReviews.abc).toStrictEqual(['123', 'hash:xyz', '098', 'hash:uvw']);
});
it.each`
@ -158,7 +158,7 @@ describe('File Review(s) utilities', () => {
it('removes the file key if there are no more reviews for it', () => {
let updated = markFileReview(reviews, file, false);
updated = markFileReview(updated, { ...file, id: '098' }, false);
updated = markFileReview(updated, { ...file, id: '098', file_hash: 'uvw' }, false);
expect(updated).toStrictEqual({});
});

View File

@ -0,0 +1,65 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Jobs/SAST-IaC.latest.gitlab-ci.yml' do
subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('Jobs/SAST-IaC.latest') }
describe 'the created pipeline' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.owner }
let(:default_branch) { 'main' }
let(:pipeline_ref) { default_branch }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_ref) }
let(:pipeline) { service.execute!(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
stub_ci_pipeline_yaml_file(template.content)
allow_next_instance_of(Ci::BuildScheduleWorker) do |instance|
allow(instance).to receive(:perform).and_return(true)
end
allow(project).to receive(:default_branch).and_return(default_branch)
end
context 'on feature branch' do
let(:pipeline_ref) { 'feature' }
it 'creates the kics-iac-sast job' do
expect(build_names).to contain_exactly('kics-iac-sast')
end
end
context 'on merge request' do
let(:service) { MergeRequests::CreatePipelineService.new(project: project, current_user: user) }
let(:merge_request) { create(:merge_request, :simple, source_project: project) }
let(:pipeline) { service.execute(merge_request).payload }
it 'has no jobs' do
expect(pipeline).to be_merge_request_event
expect(build_names).to be_empty
end
end
context 'SAST_DISABLED is set' do
before do
create(:ci_variable, key: 'SAST_DISABLED', value: 'true', project: project)
end
context 'on default branch' do
it 'has no jobs' do
expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError)
end
end
context 'on feature branch' do
let(:pipeline_ref) { 'feature' }
it 'has no jobs' do
expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError)
end
end
end
end
end