Skip to content
Snippets Groups Projects
Verified Commit 63a17314 authored by Rémy Coutable's avatar Rémy Coutable
Browse files

New task, doc, and template for security releases


Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parent 529d8437
No related branches found
No related tags found
1 merge request!42WIP: New task, doc, and template for security releases
Pipeline #
Loading
Loading
@@ -35,6 +35,10 @@ def skip?(repo)
ENV[repo.upcase] == 'false'
end
 
def security_release?
ENV['SECURITY'] == 'true'
end
desc "Create release"
task :release, [:version] do |t, args|
version = get_version(args)
Loading
Loading
@@ -43,14 +47,14 @@ task :release, [:version] do |t, args|
$stdout.puts 'Skipping release for EE'.colorize(:red)
else
$stdout.puts 'EE release'.colorize(:blue)
Release::GitlabEeRelease.new("#{version}-ee").execute
Release::GitlabEeRelease.new("#{version}-ee", security: security_release?).execute
end
 
if skip?('ce')
$stdout.puts 'Skipping release for CE'.colorize(:red)
else
$stdout.puts 'CE release'.colorize(:blue)
Release::GitlabCeRelease.new(version).execute
Release::GitlabCeRelease.new(version, security: security_release?).execute
end
end
 
Loading
Loading
@@ -111,3 +115,11 @@ task :patch_issue, [:version] do |t, args|
 
create_or_show_issue(issue)
end
desc "Create a security patch issue"
task :security_patch_issue, [:version] do |t, args|
version = get_version(args)
issue = SecurityPatchIssue.new(version)
create_or_show_issue(issue)
end
Loading
Loading
@@ -67,6 +67,29 @@ bundle exec rake "patch_issue[8.3.1]"
https://gitlab.com/gitlab-org/gitlab-ce/issues/4245
```
 
## `security_patch_issue[version]`
This task will either return the URL of a patch issue if one already exists for
`version`, or it will create a new one and return the URL.
An issue created with this Rake task has the following properties:
- Its title is "Release X.Y.Z" (e.g., "Release 8.3.1")
- Its description is the security patch release issue template
- It is assigned to the authenticated user
- It is assigned to the release's milestone
- It is labeled "Release"
- It is confidential
### Examples
```sh
bundle exec rake "security_patch_issue[8.3.1]"
--> Issue "Release 8.3.1" created.
https://gitlab.com/gitlab-org/gitlab-ce/issues/4245
```
## `regression_issue[version]`
 
This task will either return the URL of a regression issue if one already exists
Loading
Loading
Loading
Loading
@@ -31,24 +31,7 @@ will be decided on a case-by-case basis.
If a security fix warrants backporting to previous releases, doing a single blog
post that mentions all of the patches at once is acceptable.
 
## Overall process
Follow the standard [patch release process](patch.md#process), with some
additional considerations:
1. Mark any applicable previous releases as vulnerable on [version.gitlab.com].
1. Ensure the blog post discloses as much information about the vulnerability as
is responsibly possible. We aim for clarity and transparency, and try to
avoid secrecy and ambiguity.
1. Coordinate with the Marketing team to send out a security newsletter.
1. If the vulnerability was responsibly disclosed to us by a security
researcher, ensure they're [publicly acknowledged] and thank them again
privately as well.
[version.gitlab.com]: https://version.gitlab.com/
[publicly acknowledged]: https://about.gitlab.com/vulnerability-acknowledgements/
## Technical process
## Process
 
### Before the release
 
Loading
Loading
@@ -63,6 +46,25 @@ with the `dev` remote**:
https://dev.gitlab.org/gitlab/gitlab-ee against the
[`security` branch](https://dev.gitlab.org/gitlab/gitlab-ee/tree/security)
 
### 1. Create an issue to track the security patch release
In order to keep track of the various tasks that need to happen before a security
patch release is considered "complete", we create an issue on the [GitLab CE issue
tracker] and update it as we progress.
1. Create the issue using the [`security_patch_issue`](rake-tasks.md#security_patch_issueversion)
Rake task:
```sh
# NOTE: This command is an example! Update it to reflect new version numbers.
bundle exec rake "security_patch_issue[version]"
```
### 2. Complete the security patch release tasks
Use the security patch issue created earlier to keep track of the process and
mark off tasks as you complete them.
### About the security branch
 
The `security` branch is "parallel" to `master` and ensure no one inadvertedly
Loading
Loading
@@ -73,15 +75,6 @@ a manual and conscious operation.
only be merged once all the security fixes it contains are released as part of
official releases (and possibly backports).
 
### Cherry-picking
As usual cherry-pick the merge request commits you need, but this time **push to
`dev` only**:
```shell
$ git push dev X-Y-stable
```
### Merging CE stable into EE stable
 
To merge CE into EE stable, you can either add
Loading
Loading
Loading
Loading
@@ -27,6 +27,10 @@ class BaseIssue
end
end
 
def confidential?
false
end
protected
 
def template
Loading
Loading
Loading
Loading
@@ -50,7 +50,8 @@ class GitlabClient
description: issue.description,
assignee_id: current_user.id,
milestone_id: milestone.id,
labels: issue.labels
labels: issue.labels,
confidential: issue.confidential?
})
end
 
Loading
Loading
Loading
Loading
@@ -7,7 +7,7 @@ module Release
private
 
def remotes
Remotes.ce_remotes
Remotes.remotes(:ce, dev_only: options[:security])
end
 
def after_execute_hook
Loading
Loading
Loading
Loading
@@ -5,7 +5,7 @@ module Release
private
 
def remotes
Remotes.ee_remotes
Remotes.remotes(:ee, dev_only: options[:security])
end
end
end
Loading
Loading
@@ -8,7 +8,7 @@ module Release
private
 
def remotes
Remotes.omnibus_gitlab_remotes
Remotes.remotes(:omnibus_gitlab, dev_only: options[:security])
end
 
def version_class
Loading
Loading
module Remotes
def self.ce_remotes
require 'active_support/core_ext/hash/slice'
CE_REMOTES =
{
dev: 'git@dev.gitlab.org:gitlab/gitlabhq.git',
gitlab: 'git@gitlab.com:gitlab-org/gitlab-ce.git',
github: 'git@github.com:gitlabhq/gitlabhq.git'
}
end
}.freeze
 
def self.ee_remotes
EE_REMOTES =
{
dev: 'git@dev.gitlab.org:gitlab/gitlab-ee.git',
gitlab: 'git@gitlab.com:gitlab-org/gitlab-ee.git'
}
end
}.freeze
 
def self.omnibus_gitlab_remotes
OMNIBUS_GITLAB_REMOTES =
{
dev: 'git@dev.gitlab.org:gitlab/omnibus-gitlab.git',
gitlab: 'git@gitlab.com:gitlab-org/omnibus-gitlab.git',
github: 'git@github.com:gitlabhq/omnibus-gitlab.git'
}
}.freeze
def self.remotes(repo_key, dev_only: false)
remotes =
case repo_key
when :ce
CE_REMOTES
when :ee
EE_REMOTES
when :omnibus_gitlab
OMNIBUS_GITLAB_REMOTES
end
if dev_only
remotes.slice(:dev)
else
remotes
end
end
end
Loading
Loading
@@ -10,11 +10,15 @@ class Repository
class CanonicalRemote < Struct.new(:name, :url); end
 
def self.get(remotes, repository_name = nil)
repository_name ||= remotes.values.first.split('/').last.sub(/\.git\Z/, '')
repository_name ||= timestamped_name(remotes.values.first.split('/').last.sub(/\.git\Z/, ''))
 
Repository.new(File.join('/tmp', repository_name), remotes)
end
 
def self.timestamped_name(name)
"-#{Time.now.to_i}"
end
attr_reader :path, :remotes, :canonical_remote
 
def initialize(path, remotes)
Loading
Loading
require_relative 'patch_issue'
class SecurityPatchIssue < PatchIssue
def confidential?
true
end
protected
def template_path
File.expand_path('../templates/security_patch.md.erb', __dir__)
end
end
require 'spec_helper'
require 'remotes'
describe Remotes do
describe '.remotes' do
describe 'CE remotes' do
context 'without the dev_only flag' do
it 'returns all remotes' do
expect(described_class.remotes(:ce)).
to eq({
dev: 'git@dev.gitlab.org:gitlab/gitlabhq.git',
gitlab: 'git@gitlab.com:gitlab-org/gitlab-ce.git',
github: 'git@github.com:gitlabhq/gitlabhq.git'
})
end
end
context 'with the dev_only flag' do
it 'returns only the dev remote' do
expect(described_class.remotes(:ce, dev_only: true)).
to eq({
dev: 'git@dev.gitlab.org:gitlab/gitlabhq.git'
})
end
end
end
describe 'EE remotes' do
context 'without the dev_only flag' do
it 'returns all remotes' do
expect(described_class.remotes(:ee)).
to eq({
dev: 'git@dev.gitlab.org:gitlab/gitlab-ee.git',
gitlab: 'git@gitlab.com:gitlab-org/gitlab-ee.git'
})
end
end
context 'with the dev_only flag' do
it 'returns only the dev remote' do
expect(described_class.remotes(:ee, dev_only: true)).
to eq({
dev: 'git@dev.gitlab.org:gitlab/gitlab-ee.git'
})
end
end
end
describe 'Omnibus GitLab remotes' do
context 'without the dev_only flag' do
it 'returns all remotes' do
expect(described_class.remotes(:omnibus_gitlab)).
to eq({
dev: 'git@dev.gitlab.org:gitlab/omnibus-gitlab.git',
gitlab: 'git@gitlab.com:gitlab-org/omnibus-gitlab.git',
github: 'git@github.com:gitlabhq/omnibus-gitlab.git'
})
end
end
context 'with the dev_only flag' do
it 'returns only the dev remote' do
expect(described_class.remotes(:omnibus_gitlab, dev_only: true)).
to eq({
dev: 'git@dev.gitlab.org:gitlab/omnibus-gitlab.git'
})
end
end
end
end
end
require 'spec_helper'
require 'security_patch_issue'
require 'version'
describe SecurityPatchIssue do
describe '#title' do
it 'returns the issue title' do
issue = described_class.new(Version.new('8.3.1'))
expect(issue.title).to eq 'Release 8.3.1'
expect(issue).to be_confidential
end
end
describe '#description' do
it 'includes steps to push to dev only' do
issue = described_class.new(Version.new('8.3.1'))
allow(issue).to receive(:regression_issue).and_return(spy)
content = issue.description
aggregate_failures do
expect(content).to include '**Push `ce/8-3-stable` to `dev` only: `git push dev 8-3-stable`**'
expect(content).to include '**Push `ee/8-3-stable-ee` to `dev` only: `git push dev 8-3-stable-ee`**'
expect(content).to include '**Push `omnibus-gitlab/8-3-stable` to `dev` only: `git push dev 8-3-stable`**'
expect(content).to include '**Push `omnibus-gitlab/8-3-stable-ee` to `dev` only: `git push dev 8-3-stable-ee`**'
end
end
it 'includes a step to create the blog post in a private snippet' do
issue = described_class.new(Version.new('8.3.1'))
allow(issue).to receive(:regression_issue).and_return(spy)
content = issue.description
expect(content).to include 'While waiting for tests to be green, now is a good time to start on the blog post, **in a private snippet**: BLOG_POST_SNIPPET'
end
it 'includes a step to redact sensitive information from confidential security issues' do
issue = described_class.new(Version.new('8.3.1'))
allow(issue).to receive(:regression_issue).and_return(spy)
content = issue.description
expect(content).to include 'Check any sensitive information from the confidential security issues, and redact them if needed'
end
it 'includes a step to make the confidential security issues public' do
issue = described_class.new(Version.new('8.3.1'))
allow(issue).to receive(:regression_issue).and_return(spy)
content = issue.description
expect(content).to include 'Make the confidential security issues public'
end
end
end
**Be sure to follow the [Security Releases guide](https://gitlab.com/gitlab-org/release-tools/blob/master/doc/security.md).**
- Picked into respective `stable` branches from the `dev/security` branch. [`Picked into Stable` <%= version.to_minor %> merged merge requests]:
- [ ] REFERENCE_TO_MR_TO_PICK
- [ ] Check [`ce/<%= version.stable_branch %>` CHANGELOG][ce-stable-changelog]
- [ ] **Push `ce/<%= version.stable_branch %>` to `dev` only: `git push dev <%= version.stable_branch %>`**
- [ ] Check [`ee/<%= version.stable_branch(ee: true) %>` CHANGELOG-EE][ee-stable-changelog]
- [ ] **Push `ee/<%= version.stable_branch(ee: true) %>` to `dev` only: `git push dev <%= version.stable_branch(ee: true) %>`**
- [ ] Merge `ce/<%= version.stable_branch %>` into `ee/<%= version.stable_branch(ee: true) %>` following [the security process]
- [ ] Check [`omnibus-gitlab/<%= version.stable_branch %>` CHANGELOG][omnibus-stable-changelog]
- [ ] Check [`omnibus-gitlab/<%= version.stable_branch(ee: true) %>` CHANGELOG][omnibus-stable-ee-changelog]
- [ ] **Push `omnibus-gitlab/<%= version.stable_branch %>` to `dev` only: `git push dev <%= version.stable_branch %>`**
- [ ] **Push `omnibus-gitlab/<%= version.stable_branch(ee: true) %>` to `dev` only: `git push dev <%= version.stable_branch(ee: true) %>`**
- [ ] While waiting for tests to be green, now is a good time to start on [the blog post], **in a private snippet**: BLOG_POST_SNIPPET
- [ ] Ensure the blog post discloses as much information about the vulnerability as is responsibly possible. We aim for clarity and transparency, and try to avoid secrecy and ambiguity.
- [ ] If the vulnerability was responsibly disclosed to us by a security researcher, ensure they're [publicly acknowledged] and thank them again privately as well.
- [ ] Ensure [tests are green on CE]
- [ ] Ensure [tests are green on EE]
- [ ] Check for any problematic migrations in EE (EE migrations include CE ones), and paste the diff in a snippet: `git diff <%= version.previous_tag(ee: true) %>..<%= version.stable_branch(ee: true) %> -- db/migrate` =>
- [ ] Tag the `<%= version.to_patch %>` version using the [`release` task]:
```sh
bundle exec rake "release[<%= version.to_patch %>]"
```
- [ ] Check that [EE packages are built], [CE packages are built] and appears on `packages.gitlab.com`: [EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=<%= version.to_patch %>) / [CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=<%= version.to_patch %>)
- [ ] In `#infrastructure`:
```
I'm going to deploy `<%= version.to_patch %>` to staging
```
- [ ] Deploy [`<%= version %>`](https://packages.gitlab.com/gitlab/gitlab-ee/packages/ubuntu/xenial/gitlab-ee_<%= version %>-ee.0_amd64.deb) to [staging.gitlab.com]
- [ ] In `#infrastructure`:
```
I'm going to deploy `<%= version.to_patch %>` to production
```
- [ ] Deploy [`<%= version %>`](https://packages.gitlab.com/gitlab/gitlab-ee/packages/ubuntu/xenial/gitlab-ee_<%= version %>-ee.0_amd64.deb) to [GitLab.com]
- [ ] Check that the `<%= version %>` version was automatically created on https://version.gitlab.com
- [ ] Mark any applicable previous releases as vulnerable on https://version.gitlab.com.
- [ ] Check any sensitive information from the confidential security issues, and redact them if needed
- [ ] Create the blog post merge request
- [ ] Deploy the blog post
- [ ] Make the confidential security issues public
- [ ] Tweet (prepare the Tweet text below or paste the tweet URL instead):
```
GitLab <%= version %> is released! BLOG_POST_URL DESCRIPTION OF THE CHANGES
```
- [ ] Coordinate with the Marketing team to send out a security newsletter
- In the [<%= regression_issue.title %>](<%= regression_issue.url %>) issue:
- [ ] Add the following notice:
```
`<%= version %>` has been tagged, further fixes will go into `<%= version.next_patch %>` as necessary.
```
- [ ] Remove notes for the regressions fixed by version `<%= version %>`
- [ ] Add [`ce/<%= version.tag %>` CHANGELOG][ce-tag-changelog] items to [`ce/master` CHANGELOG][ce-master-changelog]
- [ ] Add [`ee/<%= version.tag(ee: true) %>` CHANGELOG-EE][ee-tag-changelog] items to [`ee/master` CHANGELOG-EE][ee-master-changelog]
- [ ] Add [`omnibus-gitlab/<%= version.tag %>+ee.0` CHANGELOG][omnibus-tag-changelog] items to [`omnibus-gitlab/master` CHANGELOG][omnibus-master-changelog]
- [ ] Create the next patch issue (if needed) using the [`patch_issue` task] (and put a reference to it below):
```sh
bundle exec rake "patch_issue[<%= version.next_patch %>]"
```
---
For references:
- https://dev.gitlab.org/gitlab/gitlab-ee/commits/<%= version.stable_branch(ee: true) %>
- https://dev.gitlab.org/gitlab/gitlabhq/commits/<%= version.stable_branch %>
- https://dev.gitlab.org/gitlab/omnibus-gitlab/commits/<%= version.stable_branch(ee: true) %>
- https://dev.gitlab.org/gitlab/omnibus-gitlab/commits/<%= version.stable_branch %>
[`Picked into Stable` <%= version.to_minor %> merged merge requests]: https://gitlab.com/groups/gitlab-org/merge_requests?label_name%5B%5D=Pick+into+Stable&milestone_title=<%= version.milestone_name %>&scope=all&sort=id_desc&state=merged
[ce-stable-changelog]: https://gitlab.com/gitlab-org/gitlab-ce/blob/<%= version.stable_branch %>/CHANGELOG
[ee-stable-changelog]: https://gitlab.com/gitlab-org/gitlab-ee/blob/<%= version.stable_branch(ee: true) %>/CHANGELOG-EE
[omnibus-stable-changelog]: https://gitlab.com/gitlab-org/omnibus-gitlab/blob/<%= version.stable_branch %>/CHANGELOG.md
[omnibus-stable-ee-changelog]: https://gitlab.com/gitlab-org/omnibus-gitlab/blob/<%= version.stable_branch(ee: true) %>/CHANGELOG.md
[tests are green on CE]: https://dev.gitlab.org/gitlab/gitlabhq/commits/<%= version.stable_branch %>
[tests are green on EE]: https://dev.gitlab.org/gitlab/gitlab-ee/commits/<%= version.stable_branch(ee: true) %>
[EE packages are built]: https://dev.gitlab.org/gitlab/omnibus-gitlab/commits/8-10-stable-ee
[CE packages are built]: https://dev.gitlab.org/gitlab/omnibus-gitlab/commits/8-10-stable
[ce-tag-changelog]: https://gitlab.com/gitlab-org/gitlab-ce/blob/<%= version.tag %>/CHANGELOG
[ee-tag-changelog]: https://gitlab.com/gitlab-org/gitlab-ee/blob/<%= version.tag(ee: true) %>/CHANGELOG-EE
[omnibus-tag-changelog]: https://gitlab.com/gitlab-org/omnibus-gitlab/blob/<%= version.tag %>+ee.0/CHANGELOG.md
[ce-master-changelog]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CHANGELOG
[ee-master-changelog]: https://gitlab.com/gitlab-org/gitlab-ee/blob/master/CHANGELOG-EE
[omnibus-master-changelog]: https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/CHANGELOG.md
[EE packages are built]: https://dev.gitlab.org/gitlab/omnibus-gitlab/commits/<%= version.stable_branch(ee: true) %>
[CE packages are built]: https://dev.gitlab.org/gitlab/omnibus-gitlab/commits/<%= version.stable_branch %>
[`gitlab/gitlab-ee`]: https://packages.gitlab.com/gitlab/gitlab-ee
[`gitlab/gitlab-ce`]: https://packages.gitlab.com/gitlab/gitlab-ce
[`release` task]: https://gitlab.com/gitlab-org/release-tools/blob/master/doc%2Frake-tasks.md#releaseversion
[`patch_issue` task]: https://gitlab.com/gitlab-org/release-tools/blob/master/doc%2Frake-tasks.md#patch_issueversion
[staging.gitlab.com]: https://dev.gitlab.org/cookbooks/chef-repo/blob/master/doc/staging.md
[GitLab.com]: https://dev.gitlab.org/cookbooks/chef-repo/blob/master/doc/deploying.md
[publicly acknowledged]: https://about.gitlab.com/vulnerability-acknowledgements/
[the blog post]: https://gitlab.com/gitlab-org/release-tools/blob/master/doc/security.md#about-the-blog-post
[the security process]: https://gitlab.com/gitlab-org/release-tools/blob/master/doc/security.md#merging-ce-stable-into-ee-stable
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment