gitlab-security_report_schemas 0.1.0.min0.0.0.max0.0.0 → 0.1.0.min15.0.0.max15.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +3 -3
  3. data/README.md +27 -4
  4. data/RUNBOOK.md +28 -0
  5. data/Rakefile +14 -3
  6. data/gem_version +1 -1
  7. data/gitlab-security_report_schemas.gemspec +33 -0
  8. data/lib/gitlab/security_report_schemas/cli/schema_checker/remote_file.rb +9 -2
  9. data/lib/gitlab/security_report_schemas/cli/schema_downloader.rb +1 -3
  10. data/lib/gitlab/security_report_schemas/configuration.rb +27 -2
  11. data/lib/gitlab/security_report_schemas/release/bundler.rb +34 -0
  12. data/lib/gitlab/security_report_schemas/release/gemfile.rb +49 -0
  13. data/lib/gitlab/security_report_schemas/release/issue.rb +77 -0
  14. data/lib/gitlab/security_report_schemas/release/merge_request.rb +84 -0
  15. data/lib/gitlab/security_report_schemas/release/templates/issue_description.erb +13 -0
  16. data/lib/gitlab/security_report_schemas/release/workflow.rb +108 -0
  17. data/lib/gitlab/security_report_schemas/schema_ver.rb +7 -4
  18. data/lib/gitlab/security_report_schemas/version.rb +0 -2
  19. data/lib/gitlab/security_report_schemas.rb +7 -3
  20. data/schemas/15.0.0/cluster-image-scanning-report-format.json +946 -0
  21. data/schemas/15.0.0/container-scanning-report-format.json +880 -0
  22. data/schemas/15.0.0/coverage-fuzzing-report-format.json +836 -0
  23. data/schemas/15.0.0/dast-report-format.json +1241 -0
  24. data/schemas/15.0.0/dependency-scanning-report-format.json +944 -0
  25. data/schemas/15.0.0/sast-report-format.json +831 -0
  26. data/schemas/15.0.0/secret-detection-report-format.json +854 -0
  27. data/schemas/15.0.1/cluster-image-scanning-report-format.json +980 -0
  28. data/schemas/15.0.1/container-scanning-report-format.json +914 -0
  29. data/schemas/15.0.1/coverage-fuzzing-report-format.json +870 -0
  30. data/schemas/15.0.1/dast-report-format.json +1275 -0
  31. data/schemas/15.0.1/dependency-scanning-report-format.json +978 -0
  32. data/schemas/15.0.1/sast-report-format.json +865 -0
  33. data/schemas/15.0.1/secret-detection-report-format.json +888 -0
  34. data/schemas/15.0.2/cluster-image-scanning-report-format.json +980 -0
  35. data/schemas/15.0.2/container-scanning-report-format.json +912 -0
  36. data/schemas/15.0.2/coverage-fuzzing-report-format.json +870 -0
  37. data/schemas/15.0.2/dast-report-format.json +1275 -0
  38. data/schemas/15.0.2/dependency-scanning-report-format.json +978 -0
  39. data/schemas/15.0.2/sast-report-format.json +865 -0
  40. data/schemas/15.0.2/secret-detection-report-format.json +888 -0
  41. data/schemas/15.0.4/cluster-image-scanning-report-format.json +984 -0
  42. data/schemas/15.0.4/container-scanning-report-format.json +916 -0
  43. data/schemas/15.0.4/coverage-fuzzing-report-format.json +874 -0
  44. data/schemas/15.0.4/dast-report-format.json +1279 -0
  45. data/schemas/15.0.4/dependency-scanning-report-format.json +982 -0
  46. data/schemas/15.0.4/sast-report-format.json +869 -0
  47. data/schemas/15.0.4/secret-detection-report-format.json +893 -0
  48. data/schemas/15.0.5/cluster-image-scanning-report-format.json +1035 -0
  49. data/schemas/15.0.5/container-scanning-report-format.json +967 -0
  50. data/schemas/15.0.5/coverage-fuzzing-report-format.json +925 -0
  51. data/schemas/15.0.5/dast-report-format.json +1330 -0
  52. data/schemas/15.0.5/dependency-scanning-report-format.json +1033 -0
  53. data/schemas/15.0.5/sast-report-format.json +920 -0
  54. data/schemas/15.0.5/secret-detection-report-format.json +944 -0
  55. data/schemas/15.0.6/cluster-image-scanning-report-format.json +1035 -0
  56. data/schemas/15.0.6/container-scanning-report-format.json +967 -0
  57. data/schemas/15.0.6/coverage-fuzzing-report-format.json +925 -0
  58. data/schemas/15.0.6/dast-report-format.json +1330 -0
  59. data/schemas/15.0.6/dependency-scanning-report-format.json +1033 -0
  60. data/schemas/15.0.6/sast-report-format.json +920 -0
  61. data/schemas/15.0.6/secret-detection-report-format.json +944 -0
  62. data/schemas/15.0.7/cluster-image-scanning-report-format.json +1085 -0
  63. data/schemas/15.0.7/container-scanning-report-format.json +1017 -0
  64. data/schemas/15.0.7/coverage-fuzzing-report-format.json +975 -0
  65. data/schemas/15.0.7/dast-report-format.json +1380 -0
  66. data/schemas/15.0.7/dependency-scanning-report-format.json +1083 -0
  67. data/schemas/15.0.7/sast-report-format.json +970 -0
  68. data/schemas/15.0.7/secret-detection-report-format.json +994 -0
  69. data/schemas/15.1.0/cluster-image-scanning-report-format.json +1065 -0
  70. data/schemas/15.1.0/container-scanning-report-format.json +997 -0
  71. data/schemas/15.1.0/coverage-fuzzing-report-format.json +975 -0
  72. data/schemas/15.1.0/dast-report-format.json +1380 -0
  73. data/schemas/15.1.0/dependency-scanning-report-format.json +986 -0
  74. data/schemas/15.1.0/sast-report-format.json +970 -0
  75. data/schemas/15.1.0/secret-detection-report-format.json +994 -0
  76. data/schemas/15.1.1/cluster-image-scanning-report-format.json +1065 -0
  77. data/schemas/15.1.1/container-scanning-for-registry-report-format.json +0 -0
  78. data/schemas/15.1.1/container-scanning-report-format.json +998 -0
  79. data/schemas/15.1.1/coverage-fuzzing-report-format.json +975 -0
  80. data/schemas/15.1.1/dast-report-format.json +1380 -0
  81. data/schemas/15.1.1/dependency-scanning-report-format.json +986 -0
  82. data/schemas/15.1.1/sast-report-format.json +970 -0
  83. data/schemas/15.1.1/secret-detection-report-format.json +994 -0
  84. data/schemas/15.1.2/cluster-image-scanning-report-format.json +1190 -0
  85. data/schemas/15.1.2/container-scanning-report-format.json +1123 -0
  86. data/schemas/15.1.2/coverage-fuzzing-report-format.json +1100 -0
  87. data/schemas/15.1.2/dast-report-format.json +1505 -0
  88. data/schemas/15.1.2/dependency-scanning-report-format.json +1111 -0
  89. data/schemas/15.1.2/sast-report-format.json +1095 -0
  90. data/schemas/15.1.2/secret-detection-report-format.json +1119 -0
  91. data/schemas/15.1.3/cluster-image-scanning-report-format.json +1190 -0
  92. data/schemas/15.1.3/container-scanning-report-format.json +1123 -0
  93. data/schemas/15.1.3/coverage-fuzzing-report-format.json +1100 -0
  94. data/schemas/15.1.3/dast-report-format.json +1505 -0
  95. data/schemas/15.1.3/dependency-scanning-report-format.json +1111 -0
  96. data/schemas/15.1.3/sast-report-format.json +1095 -0
  97. data/schemas/15.1.3/secret-detection-report-format.json +1119 -0
  98. data/schemas/15.1.4/cluster-image-scanning-report-format.json +1190 -0
  99. data/schemas/15.1.4/container-scanning-report-format.json +1123 -0
  100. data/schemas/15.1.4/coverage-fuzzing-report-format.json +1100 -0
  101. data/schemas/15.1.4/dast-report-format.json +1505 -0
  102. data/schemas/15.1.4/dependency-scanning-report-format.json +1111 -0
  103. data/schemas/15.1.4/sast-report-format.json +1095 -0
  104. data/schemas/15.1.4/secret-detection-report-format.json +1119 -0
  105. data/supported_versions +12 -0
  106. metadata +112 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48bb6ab237a896e1a713f7384008e510307fc383135450eca126ce5c912250bd
4
- data.tar.gz: b1b4f46ea3c0e83ee3967a418b71a93039ab4227b0f6beae3487b8ed568a4116
3
+ metadata.gz: eb0ee095cc1634e7242faa1990caf178447e8774e0c1027665388b24494c7b9c
4
+ data.tar.gz: eb1cd4245ced146a0d1f01769f1d60117e4b8cf36e51106abe6c7632096c0a40
5
5
  SHA512:
6
- metadata.gz: d92c6d99fa5605d114247a642e386a0876de1396a080868b55ce05951e51b30eb7768fc0c3846b311360a8f6c44f930224a9f7ef2c2f96af1881eed14e2b82f1
7
- data.tar.gz: 3e21bfff0c8c1a3dfae2831b92546a513a89b85475f20d5c68303711580881a174e2160f91e23f4457a689063e6dc16ea28e5050201f6a4fbeb7d6af7d483377
6
+ metadata.gz: 0d8aaaff8004ceb08b6cd1e1bfbde2b330ac45b66c3dc9c9d132b08d13dd2ea4137766ff4b87ce9789577f51df0ba3095e1a0f893341d9364cd88f19f160118b
7
+ data.tar.gz: a2c6dd7ff0729f43591b798e17adaf0830ece329356e200cd08c1cec772b47234b437705049b6dedce7ab587a0f41ef729c3048a5e5da5a0a883b28c26f8cbd1
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab-security_report_schemas (0.1.0.min0.0.0.max0.0.0)
5
- activesupport (>= 5)
4
+ gitlab-security_report_schemas (0.1.0.min15.0.0.max15.1.4)
5
+ activesupport (>= 6, < 8)
6
6
  json_schemer (~> 0.2.18)
7
7
 
8
8
  GEM
@@ -91,4 +91,4 @@ DEPENDENCIES
91
91
  shoulda-matchers (~> 5.0)
92
92
 
93
93
  BUNDLED WITH
94
- 2.3.15
94
+ 2.5.14
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
- [![pipeline status](https://gitlab.com/gitlab-org/security-products/security-report-schemas-ruby/badges/main/pipeline.svg)](https://gitlab.com/gitlab-org/security-products/security-report-schemas-ruby/-/commits/main)
2
- [![coverage report](https://gitlab.com/gitlab-org/security-products/security-report-schemas-ruby/badges/main/coverage.svg)](https://gitlab.com/gitlab-org/security-products/security-report-schemas-ruby/-/commits/main)
3
- [![Latest Release](https://gitlab.com/gitlab-org/security-products/security-report-schemas-ruby/-/badges/release.svg)](https://gitlab.com/gitlab-org/security-products/security-report-schemas-ruby/-/releases)
1
+ [![pipeline status](https://gitlab.com/gitlab-org/ruby/gems/gitlab-security_report_schemas/badges/main/pipeline.svg)](https://gitlab.com/gitlab-org/ruby/gems/gitlab-security_report_schemas/-/commits/main)
2
+ [![coverage report](https://gitlab.com/gitlab-org/ruby/gems/gitlab-security_report_schemas/badges/main/coverage.svg)](https://gitlab.com/gitlab-org/ruby/gems/gitlab-security_report_schemas/-/commits/main)
3
+ [![Latest Release](https://gitlab.com/gitlab-org/ruby/gems/gitlab-security_report_schemas/-/badges/release.svg)](https://gitlab.com/gitlab-org/ruby/gems/gitlab-security_report_schemas/-/releases)
4
4
 
5
5
  # Gitlab::SecurityReportSchemas
6
6
 
7
- Rubygem for https://gitlab.com/gitlab-org/security-products/security-reports-schema
7
+ Rubygem for https://gitlab.com/gitlab-org/security-products/security-report-schemas/
8
8
 
9
9
  This gem provides a Ruby and command line interface to validate the report artifact generated by the security analyzers.
10
10
 
@@ -43,6 +43,29 @@ You can use the executable to check validity of your report artifact, like so;
43
43
  bundle exec security-reports-schemas $FILE_PATH
44
44
  ```
45
45
 
46
+ ### Environment variables
47
+
48
+ #### Credentials
49
+
50
+ | Key | Description |
51
+ |-----------------------------|-----------------------------------------------------------------------------------------------|
52
+ | `GITLAB_PUSH_ACCESS_TOKEN` | Own project access token used to push new schema versions. Requires `write_repository` scope. |
53
+ | `GITLAB_ISSUE_ACCESS_TOKEN` | Project access token used to create an issue on `gitlab-org/gitlab`. Requires `api` scopes. |
54
+ | `GEM_HOST_API_KEY` | rubygems.org API key |
55
+
56
+ #### Configuration
57
+
58
+ | Key | Default | Description |
59
+ |---------------------------|--------------------------------------------------------|----------------------------------------|
60
+ | `SCHEMAS_PATH` | `./schemas` | Schema storage location |
61
+ | `SCHEMA_PROJECT` | `gitlab-org/security-products/security-report-schemas` | Where to source schemas |
62
+ | `GITLAB_PROJECT` | `gitlab-org/gitlab` | Project to open MRs for |
63
+ | `ISSUE_TARGET_PROJECT_ID` | `278964` (`gitlab-org/gitlab`) | Project ID for which to open an issue. |
64
+
65
+ ## Maintenance
66
+
67
+ See [`RUNBOOK.md`](./RUNBOOK.md) for solutions to common maintenance tasks.
68
+
46
69
  ## Development
47
70
 
48
71
  ### Updating the schemas
data/RUNBOOK.md ADDED
@@ -0,0 +1,28 @@
1
+ # Common maintenance tasks
2
+
3
+ ### Problem
4
+
5
+ * an upstream [security-report-schemas](https://gitlab.com/gitlab-org/security-products/security-report-schemas) pipeline failed to trigger the release pipeline
6
+ * you want to add, remove or deprecate support for report schema versions
7
+ * you need to release a new version of the gem without altering version ranges,
8
+ because for example:
9
+ * an existing gem release has a bug, and the bugfix release needs to cover the
10
+ same version range.
11
+ * there were breaking changes to the gem's public API that must be released
12
+ for the currently supported version range.
13
+
14
+ ### Solution
15
+
16
+ 1. Open and merge an MR targeting the default branch which may:
17
+ * change the [`supported_versions`](../supported_versions) file to set the
18
+ report schema version range that the release should include.
19
+ * change the `Gitlab::SecurityReportSchemas::Version::GEM_VERSION` constant
20
+ to set the MAJOR.MINOR.PATCH version components of the resulting release.
21
+ 2. Run a new pipeline for the default branch and set the `MANUAL_RELEASE` CI
22
+ variable.
23
+ 3. Trigger the manual `manual-release` job in the resulting pipeline.
24
+
25
+ ## Find the commit SHA for a RubyGem version
26
+
27
+ Before a rubygems.org release is created, a git tag referencing the full
28
+ v-prefixed release version is pushed, for example `v0.1.0.min15.0.0.max15.0.1`.
data/Rakefile CHANGED
@@ -17,7 +17,9 @@ task :prepare_schemas, [:versions] do |_, args|
17
17
  require "gitlab/security_report_schemas"
18
18
  require "gitlab/security_report_schemas/cli/schema_downloader"
19
19
 
20
- requested_versions = args[:versions]&.split.to_a
20
+ requested_versions = args.fetch(:versions, "").split.map do |ver|
21
+ Gitlab::SecurityReportSchemas::SchemaVer.new!(ver, fallback: false)
22
+ end
21
23
 
22
24
  cleanup_schema_dir.then { schemas_to_prepare(requested_versions) }
23
25
  .then { copy_new_schemas(_1) }
@@ -28,7 +30,7 @@ desc "Bundles the Security Report Schemas into the project and builds the gem"
28
30
  task :prepare, %i[versions] => %i[prepare_schemas build]
29
31
 
30
32
  desc "Checks the integrity of the schema files with upstream"
31
- task :integrity_check do
33
+ task integrity_check: :prepare_schemas do
32
34
  require "gitlab/security_report_schemas"
33
35
  require "gitlab/security_report_schemas/cli/integrity_checker"
34
36
 
@@ -39,6 +41,15 @@ task :integrity_check do
39
41
  end
40
42
  end
41
43
 
44
+ namespace :release do
45
+ desc "Open patch Issue on gitlab-org/gitlab to update its Gemfile to use the current gem version"
46
+ task :issue do
47
+ require "gitlab/security_report_schemas"
48
+
49
+ Gitlab::SecurityReportSchemas::Release::Workflow.execute
50
+ end
51
+ end
52
+
42
53
  def cleanup_schema_dir
43
54
  puts "Cleaning the schemas directory..."
44
55
 
@@ -57,7 +68,7 @@ def schemas_to_prepare(requested_versions)
57
68
  if requested_versions.empty?
58
69
  puts "Preparing schemas from `supported_versions' file..."
59
70
  else
60
- puts "Preparing new schemas #{requested_versions}"
71
+ puts %(Preparing new schemas #{requested_versions.map(&:version).join(",")})
61
72
  end
62
73
 
63
74
  supported_versions + requested_versions
data/gem_version CHANGED
@@ -1 +1 @@
1
- 0.1.0.min0.0.0.max0.0.0
1
+ 0.1.0.min15.0.0.max15.1.4
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "gitlab-security_report_schemas"
5
+ spec.version = `cat gem_version`
6
+ spec.authors = ["GitLab"]
7
+ spec.email = ["gitlab_rubygems@gitlab.com"]
8
+ spec.license = "Nonstandard"
9
+
10
+ spec.summary = "Ruby gem for GitLab security report JSON schemas"
11
+ spec.homepage = "https://gitlab.com/gitlab-org/ruby/gems/gitlab-security_report_schemas"
12
+ spec.required_ruby_version = ">= 2.7.0"
13
+
14
+ spec.metadata["homepage_uri"] = spec.homepage
15
+
16
+ # Specify which files should be added to the gem when it is released.
17
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
+ spec.files = Dir.chdir(__dir__) do
19
+ `git ls-files -z`.split("\x0").reject do |f|
20
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
21
+ end
22
+ end
23
+
24
+ # Bundle the schemas into the gem
25
+ spec.files += `find schemas -type f`.split("\n")
26
+
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+
31
+ spec.add_dependency "activesupport", ">= 6", "< 8"
32
+ spec.add_dependency "json_schemer", "~> 0.2.18"
33
+ end
@@ -8,7 +8,6 @@ module Gitlab
8
8
  class IntegrityChecker
9
9
  # Represents the schema file located on GitLab.com
10
10
  class RemoteFile < AbstractFile
11
- SCHEMA_PROJECT_RAW_URL = "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/v%<version>s/dist/%<schema_file_name>s"
12
11
  SCHEMA_FILE_NAME_REGEX = %r{./+(?<version>\d+\.\d+\.\d+)/(?<file_name>.+-report-format\.json)$}.freeze
13
12
 
14
13
  private
@@ -22,7 +21,7 @@ module Gitlab
22
21
  end
23
22
 
24
23
  def schema_url
25
- format(SCHEMA_PROJECT_RAW_URL, version: version, schema_file_name: schema_file_name)
24
+ format(schema_project_raw_url, version: version, schema_file_name: schema_file_name)
26
25
  end
27
26
 
28
27
  def version
@@ -36,6 +35,14 @@ module Gitlab
36
35
  def schema_file_components
37
36
  @schema_file_components ||= schema_file.to_s.match(SCHEMA_FILE_NAME_REGEX).named_captures
38
37
  end
38
+
39
+ def schema_project_raw_url
40
+ "#{schema_project_url}/-/raw/v%<version>s/dist/%<schema_file_name>s"
41
+ end
42
+
43
+ def schema_project_url
44
+ Gitlab::SecurityReportSchemas.configuration.schema_project_url
45
+ end
39
46
  end
40
47
  end
41
48
  end
@@ -8,8 +8,6 @@ module Gitlab
8
8
  module CLI
9
9
  # Copies the schema for the given version to the project
10
10
  class SchemaDownloader
11
- SCHEMA_PROJECT_REPO = "git@gitlab.com:gitlab-org/security-products/security-report-schemas.git"
12
-
13
11
  def self.download(version)
14
12
  new(version).download
15
13
  end
@@ -59,7 +57,7 @@ module Gitlab
59
57
  end
60
58
 
61
59
  def clone_repository
62
- Git.clone(SCHEMA_PROJECT_REPO, git_project_path)
60
+ Git.clone(Gitlab::SecurityReportSchemas.configuration.schema_repository, git_project_path)
63
61
  end
64
62
 
65
63
  def git_project_path
@@ -6,16 +6,41 @@ module Gitlab
6
6
  class Configuration
7
7
  OPTIONS = {
8
8
  schemas_path: -> { SecurityReportSchemas.root_path.join("schemas") },
9
- deprecated_versions: -> { [] }
9
+ deprecated_versions: -> { [] },
10
+ schema_project: -> { "gitlab-org/security-products/security-report-schemas" },
11
+ gitlab_project: -> { "gitlab-org/gitlab" },
12
+ issue_target_project_id: -> { "278964" }, # gitlab-org/gitlab
13
+ gitlab_issue_access_token: nil,
14
+ ci_server_host: nil
10
15
  }.freeze
11
16
 
12
17
  OPTIONS.each do |option, default_value|
13
18
  define_method(option) do
14
- instance_variable_get("@#{option}") || default_value.call
19
+ instance_variable_get("@#{option}") || ENV[option.upcase.to_s] || default_value&.call
15
20
  end
16
21
 
17
22
  attr_writer option
18
23
  end
24
+
25
+ def initialize
26
+ yield self if block_given?
27
+ end
28
+
29
+ def schema_project_url
30
+ "https://gitlab.com/#{schema_project}"
31
+ end
32
+
33
+ def schema_repository
34
+ "#{schema_project_url}.git"
35
+ end
36
+
37
+ def gitlab_project_url
38
+ "https://gitlab.com/#{gitlab_project}"
39
+ end
40
+
41
+ def gitlab_repository
42
+ "#{gitlab_project_url}.git"
43
+ end
19
44
  end
20
45
  end
21
46
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module SecurityReportSchemas
5
+ module Release
6
+ # Wrapper around bundle(1).
7
+ module Bundler
8
+ extend self
9
+
10
+ def install!
11
+ run("bundle install")
12
+ end
13
+
14
+ def checksum!
15
+ run("bundle exec bundler-checksum init")
16
+ end
17
+
18
+ def verify_checksum!
19
+ run("bundle exec bundler-checksum verify")
20
+ end
21
+
22
+ private
23
+
24
+ def run(command)
25
+ # Bundler modifies RUBYOPT and RUBYLIB which makes bundle(1) attempt
26
+ # to load from our gem environment instead of from the GitLab environment.
27
+ ::Bundler.with_unbundled_env do
28
+ system(command) || raise("non-zero exit code: `#{command}`")
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tempfile"
4
+
5
+ module Gitlab
6
+ module SecurityReportSchemas
7
+ module Release
8
+ # Changes or adds a dependency version to a Gemfile.
9
+ class Gemfile
10
+ SUBSTITUTION_REGEX_TEMPLATE = %{gem ['"]%s['"], ['"](.*)['"]}
11
+ FEATURE_CATEGORY = :vulnerability_management
12
+
13
+ def self.update!(workflow)
14
+ File.open(workflow.gemfile_path, "r+").tap do |file|
15
+ new(file).rewrite!(workflow.class::DEPENDENCY, workflow.gem_version)
16
+ end
17
+ end
18
+
19
+ attr_reader :file
20
+
21
+ def initialize(file)
22
+ @file = file
23
+ end
24
+
25
+ private_class_method :new
26
+
27
+ def rewrite!(dependency, version)
28
+ contents = file.read
29
+
30
+ file.seek(0)
31
+ file.truncate(0)
32
+ file.puts(substituted_content(contents, dependency, version))
33
+ end
34
+
35
+ private
36
+
37
+ def substituted_content(contents, dependency, version)
38
+ regex = Regexp.new(SUBSTITUTION_REGEX_TEMPLATE % dependency)
39
+ dep = "gem '#{dependency}', '#{version}'"
40
+
41
+ return contents.gsub!(regex, dep) if contents.match(regex)
42
+
43
+ contents.concat("#{dep}, feature_category: #{FEATURE_CATEGORY.inspect}")
44
+ contents.concat("\n") unless contents.end_with?("\n")
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module SecurityReportSchemas
5
+ module Release
6
+ # GitLab Issue creation.
7
+ class Issue
8
+ API_ROOT = "https://gitlab.com/api/v4"
9
+ DESCRIPTION_TEMPLATE = "issue_description.erb"
10
+
11
+ def self.create!(workflow)
12
+ new(workflow).execute!
13
+ end
14
+
15
+ attr_reader :workflow
16
+
17
+ def initialize(workflow)
18
+ @workflow = workflow
19
+ end
20
+
21
+ def execute!
22
+ http = Net::HTTP.new(uri.host, uri.port)
23
+ http.use_ssl = true
24
+
25
+ case response = http.request(request)
26
+ when Net::HTTPSuccess then extract_url(JSON.parse(response.body))
27
+ else raise "Failed to create issue: #{response.code} -- #{response.message}"
28
+ end
29
+ end
30
+
31
+ def uri
32
+ URI(File.join(API_ROOT, "projects", workflow.target_project_id.to_s, "issues"))
33
+ end
34
+
35
+ def body
36
+ {
37
+ title: workflow.commit_message,
38
+ description: description
39
+ }
40
+ end
41
+
42
+ def headers
43
+ {
44
+ "Content-Type" => "application/json",
45
+ "Authorization" => "Bearer #{workflow.access_token}"
46
+ }
47
+ end
48
+
49
+ def description
50
+ description_template.result_with_hash(gem_version: workflow.gem_version, patch: workflow.patch)
51
+ end
52
+
53
+ private
54
+
55
+ def request
56
+ Net::HTTP::Post.new(uri, headers).tap do |req|
57
+ req.body = body.to_json
58
+ end
59
+ end
60
+
61
+ def extract_url(body)
62
+ body["web_url"]
63
+ end
64
+
65
+ def description_template
66
+ ERB.new(File.read(description_template_path))
67
+ end
68
+
69
+ def description_template_path
70
+ Gitlab::SecurityReportSchemas.root_path.join(
71
+ "lib", "gitlab", "security_report_schemas", "release", "templates", DESCRIPTION_TEMPLATE
72
+ )
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "uri"
5
+ require "erb"
6
+ require "json"
7
+
8
+ module Gitlab
9
+ module SecurityReportSchemas
10
+ module Release
11
+ # GitLab merge request creation.
12
+ class MergeRequest
13
+ API_ROOT = "https://gitlab.com/api/v4"
14
+ DESCRIPTION_TEMPLATE = "mr_description.erb"
15
+
16
+ def self.create!(workflow)
17
+ new(workflow).execute!
18
+ end
19
+
20
+ attr_reader :workflow
21
+
22
+ def initialize(workflow)
23
+ @workflow = workflow
24
+ end
25
+
26
+ def execute!
27
+ http = Net::HTTP.new(uri.host, uri.port)
28
+ http.use_ssl = true
29
+
30
+ case response = http.request(request)
31
+ when Net::HTTPSuccess then extract_url(JSON.parse(response.body))
32
+ else raise "Failed to create merge request: #{response.code} -- #{response.message}"
33
+ end
34
+ end
35
+
36
+ def uri
37
+ URI(File.join(API_ROOT, "projects", workflow.target_project_id.to_s, "merge_requests"))
38
+ end
39
+
40
+ def body
41
+ {
42
+ source_branch: workflow.branch_name,
43
+ target_branch: workflow.class::TARGET_BRANCH,
44
+ title: workflow.commit_message,
45
+ description: description
46
+ }
47
+ end
48
+
49
+ def headers
50
+ {
51
+ "Content-Type" => "application/json",
52
+ "Authorization" => "Bearer #{workflow.access_token}"
53
+ }
54
+ end
55
+
56
+ def description
57
+ description_template.result_with_hash(gem_version: workflow.gem_version)
58
+ end
59
+
60
+ private
61
+
62
+ def request
63
+ Net::HTTP::Post.new(uri, headers).tap do |req|
64
+ req.body = body.to_json
65
+ end
66
+ end
67
+
68
+ def extract_url(body)
69
+ body["web_url"]
70
+ end
71
+
72
+ def description_template
73
+ ERB.new(File.read(description_template_path))
74
+ end
75
+
76
+ def description_template_path
77
+ Gitlab::SecurityReportSchemas.root_path.join(
78
+ "lib", "gitlab", "security_report_schemas", "release", "templates", DESCRIPTION_TEMPLATE
79
+ )
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,13 @@
1
+ This is an automatically generated Issue to update the version of [`gitlab-security_report_schemas`](https://gitlab.com/gitlab-org/ruby/gems/gitlab-security_report_schemas/) to <%= gem_version %>.
2
+
3
+ ### Patch
4
+
5
+ ```diff
6
+ <%= patch %>
7
+ ```
8
+
9
+ ### Background
10
+
11
+ GitLab Secure schemas are used as part of [Security scanner integration](https://docs.gitlab.com/ee/development/integrations/secure.html) to ensure that reports produced by analyzers are able to be parsed successfully by GitLab. Each JSON report indicates which version of the Secure schema it conforms to. When the report is parsed, the file is validated using the appropriate schema and will be rejected if it does not succeed.
12
+
13
+ /label ~section::sec
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "git"
4
+
5
+ module Gitlab
6
+ module SecurityReportSchemas
7
+ module Release
8
+ # The release workflow that updates a GitLab repository's Gemfile
9
+ # dependency on this gem to an existing version published on rubygems.org
10
+ # and creates a merge request for the change.
11
+ class Workflow
12
+ DEPENDENCY = "gitlab-security_report_schemas"
13
+ COMMIT_MESSAGE = "Bump `#{DEPENDENCY}' to v%s"
14
+ BRANCH_NAME = "#{DEPENDENCY}-v%s"
15
+ TARGET_BRANCH = "master"
16
+
17
+ def self.execute(configuration = Gitlab::SecurityReportSchemas.configuration)
18
+ new(configuration).execute
19
+ end
20
+
21
+ attr_reader :configuration
22
+
23
+ def initialize(configuration)
24
+ @configuration = configuration
25
+ end
26
+
27
+ def execute
28
+ gitlab_repository # ensure repository is cloned
29
+
30
+ update_gemfile!
31
+ install_dependencies!
32
+
33
+ issue_url = create_issue!
34
+
35
+ puts "Successfully created Issue: #{issue_url}"
36
+ end
37
+
38
+ def patch
39
+ gitlab_repository.diff.patch
40
+ end
41
+
42
+ def gemfile_path
43
+ gitlab_repository_path.join("Gemfile")
44
+ end
45
+
46
+ def gem_version
47
+ File.read(gem_version_file).strip
48
+ end
49
+
50
+ def branch_name
51
+ BRANCH_NAME % gem_version
52
+ end
53
+
54
+ def commit_message
55
+ COMMIT_MESSAGE % gem_version
56
+ end
57
+
58
+ def target_project_id
59
+ configuration.issue_target_project_id
60
+ end
61
+
62
+ def access_token
63
+ configuration.gitlab_issue_access_token
64
+ end
65
+
66
+ private
67
+
68
+ def gitlab_repository
69
+ @gitlab_repository ||= if File.exist?(gitlab_repository_path)
70
+ Git.open(gitlab_repository_path)
71
+ else
72
+ Git.clone(configuration.gitlab_repository, gitlab_repository_path, depth: 1)
73
+ end
74
+ end
75
+
76
+ def update_gemfile!
77
+ Gitlab::SecurityReportSchemas::Release::Gemfile.update!(self)
78
+ end
79
+
80
+ def install_dependencies!
81
+ bundle do
82
+ install!
83
+ checksum!
84
+ verify_checksum!
85
+ end
86
+ end
87
+
88
+ def bundle(&block)
89
+ Dir.chdir(gitlab_repository_path) do
90
+ Gitlab::SecurityReportSchemas::Release::Bundler.module_eval(&block)
91
+ end
92
+ end
93
+
94
+ def create_issue!
95
+ Gitlab::SecurityReportSchemas::Release::Issue.create!(self)
96
+ end
97
+
98
+ def gitlab_repository_path
99
+ Gitlab::SecurityReportSchemas.root_path.join("tmp", "gitlab")
100
+ end
101
+
102
+ def gem_version_file
103
+ Gitlab::SecurityReportSchemas.root_path.join("gem_version")
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -10,17 +10,20 @@ module Gitlab
10
10
 
11
11
  include Comparable
12
12
 
13
- def self.new!(version)
13
+ def self.new!(version, fallback: true)
14
14
  return SecurityReportSchemas.supported_versions.last if version.blank?
15
- raise InvalidSchemaVersion, version unless version.match(VALID_SCHEMA_FORMAT)
16
15
 
17
- new(version).itself_or_fallback
16
+ raise InvalidSchemaVersion, version unless version.match?(VALID_SCHEMA_FORMAT)
17
+
18
+ instance = new(version)
19
+
20
+ fallback ? instance.itself_or_fallback : instance
18
21
  end
19
22
 
20
23
  attr_reader :version
21
24
 
22
25
  def initialize(version)
23
- @version = version
26
+ @version = version[VALID_SCHEMA_FORMAT]
24
27
  end
25
28
 
26
29
  def itself_or_fallback