Skip to content

Commit c13fd27

Browse files
committed
docs/howto/release-git-lfs.md: add security steps
The documentation of our standard and patch release processes does not, at present, include the steps required to build a security patch release, so we add two sections which describe how we build such releases. The first new section documents our normal security patch release process, which applies when we do not need to coordinate our release with other projects, or at least do not need to build release assets in private while under a publication embargo. The second new section details the process of building new Git LFS release binaries in private, so they can be shared with other downstream projects while we are under an embargo on the publication of the security vulnerability and associated security patch release.
1 parent e76a339 commit c13fd27

File tree

1 file changed

+266
-0
lines changed

1 file changed

+266
-0
lines changed

docs/howto/release-git-lfs.md

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,3 +337,269 @@ and then use that branch as the base for the PATCH release.
337337

338338
5. Then follow the [guidelines](#building-a-release) above, using the
339339
`release-M.N` branch as the base for the new PATCH release.
340+
341+
### Building security PATCH versions
342+
343+
In our public security [policy](../../SECURITY.md) we request that
344+
potential vulnerabilities in the Git LFS client be reported to us
345+
via email. Users sometimes also choose to open draft GitHub security
346+
advisories, although we do not encourage that option.
347+
348+
If we determine that such a report is valid, we develop a PATCH release
349+
version of the client with a remediation for the security issue,
350+
following the steps below.
351+
352+
1. Open a new draft security advisory, fill out the relevant
353+
details in the
354+
[template](https://github.com/git-lfs/git-lfs/security/advisories/new),
355+
and request a CVE identifier.
356+
357+
2. Create a temporary private fork of this repository from the draft
358+
security advisory page, and use the fork to develop a resolution
359+
of the vulnerability.
360+
361+
3. Create two PRs in the private fork, one to remediate the vulnerability
362+
in the `main` development branch of the public `git-lfs/git-lfs`
363+
repository, and one to do so in the appropriate `release-M.N` branch.
364+
365+
The PR which targets the release branch should have a final, extra
366+
commit which adds an entry for the new PATCH release version in the
367+
`CHANGELOG.md` file, describing the release and the security fix it
368+
contains. This commit should also include the changes generated
369+
by the `script/update-version vM.N.P` command, as per the second step
370+
in our standard release process.
371+
372+
If the `release-M.N` branch does not exist in the public repository,
373+
create it as per our regular PATCH release process, and then create
374+
the second PR in the private fork against the new branch. Be prepared
375+
to proceed relatively quickly, since the appearance of the new branch
376+
serves as a public notice that we may be publishing a PATCH release
377+
shortly.
378+
379+
4. From the draft security advisory page, use the "Merge pull requests"
380+
option to merge both PRs simultaneously.
381+
382+
Note that both the release branch and the `main` branch in the private
383+
fork must be up-to-date with the corresponding branches in the public
384+
repository in order for the GitHub UI to determine whether the PRs have
385+
no merge conflicts.
386+
387+
5. Publish the security advisory.
388+
389+
6. Follow our standard release process, starting with the step in which
390+
we create a GPG-signed tag named `vM.N.P` on the merge commit to the
391+
`release-M.N` branch.
392+
393+
7. After publication of the new release, update the `git-lfs.com` home
394+
page with a banner message regarding the security PATCH release
395+
by pushing a change to the `_includes/home/secondary.html` file
396+
in the `git-lfs/git-lfs.github.com` repository.
397+
398+
8. Create a new discussion in the "Announcements" section of the GitHub
399+
discussion [forum](https://github.com/git-lfs/git-lfs/discussions)
400+
describing the security PATCH release, and pin the discussion for
401+
all categories in the forum.
402+
403+
### Building security PATCH versions under embargo
404+
405+
When coordinating the release of a security patch with one or more
406+
other projects, we must not follow the processes described above as
407+
they depend on the GitHub Actions release workflow in our public
408+
`git-lfs/git-lfs` repository. Instead, we use a private repository
409+
with a modified release workflow to build the binaries and packages
410+
for our new version so that we can share them with the other projects
411+
in advance of the coordinated release date.
412+
413+
1. Open a draft security advisory, apply for a CVE identifier, and
414+
create a private fork in which to develop a resolution of the
415+
vulnerability, as described above in the initial steps of our
416+
non-embargoed security PATCH release process.
417+
418+
2. Create one PR in the private fork to remediate the vulnerability
419+
in the `main` development branch of the public repository.
420+
421+
3. Create a branch in the private fork from the appropriate
422+
`release-M.N` branch, or if that does not yet exist, from the
423+
appropriate `vM.N.0` tag, and add the necessary changes to remediate
424+
the vulnerability.
425+
426+
This branch should have one extra, final commit which adds an entry
427+
for the new PATCH release version in the `CHANGELOG.md` file,
428+
describing the release and the security fix it contains. This
429+
commit should also include the changes generated by the
430+
`script/update-version vM.N.P` command, as per the second step
431+
in our standard release process.
432+
433+
4. Pull this branch from the private fork of the public repository
434+
and push it into a separate private repository which has a fresh copy
435+
of the public `git-lfs/git-lfs` repository, and for which our full
436+
CI and release GitHub Actions workflows are configured and enabled.
437+
438+
Note that the private fork created from the draft security advisory
439+
will not execute GitHub Actions jobs, and so we require the use of
440+
a separate private repository to run a modified release workflow.
441+
442+
5. If the `release-M.N` branch does not exist, create it in the
443+
separate private repository from the `vM.N.0` tag, as described
444+
in the second step of our regular PATCH release process.
445+
446+
6. Merge the branch containing the security fix and the commit with the
447+
new `CHANGELOG.md` entry (and `script/update-version vM.N.P` changes)
448+
into the `release-M.N` branch, and sign the merge commit with your
449+
GPG key:
450+
451+
```ShellSession
452+
$ git checkout release-M.N
453+
$ git merge --no-ff -S \
454+
-m "Merge pull request from GHSA-abcd-1234-wxyz" \
455+
-m "release: M.N.P" \
456+
branch-with-fix-and-changelog
457+
```
458+
459+
Use the GHSA identifier from the draft security advisory in the
460+
merge commit's description.
461+
462+
7. Create a GPG-signed tag named `vM.N.P` on the merge commit, using
463+
the same command from the equivalent step of our standard release
464+
process:
465+
466+
```ShellSession
467+
$ git tag -s vM.N.P -m vM.N.P
468+
```
469+
470+
8. Check out the `main` branch of the private repository and make
471+
several revisions to the `.github/workflows/release.yml` file,
472+
and then push these changes back to the private repository's `main`
473+
branch.
474+
475+
First, change the `on` value to `workflow_dispatch`:
476+
477+
```diff
478+
-on:
479+
- push:
480+
- tags: '*'
481+
+on: workflow_dispatch
482+
```
483+
484+
Set the version of Go in each `matrix` context to the same version
485+
used in the Dockerfiles from our `git-lfs/build-dockers` repository.
486+
487+
Replace the `${{ github.ref }}` context wherever it appears with the
488+
`vM.N.P` tag:
489+
490+
```diff
491+
- ref: ${{ github.ref }}
492+
+ ref: vM.N.P
493+
```
494+
495+
Revise the `build-docker` and `build-docker-arm` jobs so they do not
496+
upload the Linux packages generated by the `docker/run_dockers.bsh`
497+
script to Packagecloud by running the `script/packagecloud.rb` utility.
498+
Change the jobs to instead upload the Linux packages as job artifacts;
499+
for instance, for the `build-docker` job:
500+
501+
```yaml
502+
- uses: actions/upload-artifact@v4
503+
with:
504+
name: docker-assets
505+
path: |
506+
repos/**/*.deb
507+
repos/**/*.rpm
508+
```
509+
510+
Make sure to use distinct artifact `name`s for each of these jobs,
511+
i.e., `docker-assets` and `docker-arm-assets`.
512+
513+
9. Push the `vM.N.P` tag to the private repository, and then cancel
514+
the GitHub Actions job which runs from the release workflow.
515+
516+
(This workflow will run because the tag includes our normal
517+
GitHub Actions workflow definitions without the changes made in
518+
the previous step, since those exist only on the `main` branch,
519+
and we do not want to include these temporary workflow changes in
520+
the security release itself.)
521+
522+
Confirm that the CI workflow job succeeds.
523+
524+
10. From the private repository's GitHub Actions page, manually dispatch
525+
the release workflow.
526+
527+
11. When the manually-dispatched job is complete, download the
528+
`release-assets`, `docker-assets`, and `docker-arm-assets` archive
529+
files from the "Artifacts" section of the job's "Summary" page.
530+
531+
Share the relevant binaries from the archive files with the other
532+
collaborating projects during the embargo period.
533+
534+
12. Before the embargo is due to the lifted, unpack the `release-assets`
535+
archive file at the top level of this repository and use the
536+
`script/upload` utility to create a draft release announcement and
537+
attach the release assets to it, just as for a standard release:
538+
539+
```ShellSession
540+
$ rm -rf bin/releases
541+
$ unzip /path/to/release-assets.zip
542+
543+
$ script/upload --skip-verify vM.N.P
544+
```
545+
546+
13. When the embargo is lifted, use the "Merge pull requests" option
547+
on the draft security advisory page to merge the PR with the security
548+
fix into the `main` branch of the public repository.
549+
550+
Note that the `main` branch in the private fork must be up-to-date
551+
with the corresponding branch in the public repository in order for
552+
the GitHub UI to determine whether the PR has no merge conflicts.
553+
554+
14. Publish the security advisory.
555+
556+
15. Pull the `release-M.N` branch and `vM.N.P` tag from the private
557+
repository where the release workflow was run manually, and push
558+
them into the public `git-lfs/git-lfs` repository.
559+
560+
Immediately cancel the GitHub Actions job which runs from the
561+
release workflow in the public repository.
562+
563+
Note that cancelling the release workflow job is important, since
564+
it will otherwise build new versions of the RPM and Debian Linux
565+
packages and publish them to Packagecloud.
566+
567+
16. Upload to Packagecloud the RPM and Debian Linux packages in the
568+
`docker-assets` and `docker-arm-assets` archive files created earlier
569+
by the manual release workflow job.
570+
571+
Note that the `script/packagecloud.rb` utility requires the
572+
`PACKAGECLOUD_TOKEN` environment variable to contain the current
573+
Packagecloud account credential token.
574+
575+
```ShellSession
576+
$ mkdir repos
577+
$ unzip -d repos /path/to/docker-assets.zip
578+
$ unzip -d repos /path/to/docker-arm-assets.zip
579+
580+
$ gem install packagecloud-ruby
581+
$ PACKAGECLOUD_TOKEN="<token>" script/packagecloud.rb
582+
```
583+
584+
17. Finalize the release process using the `script/upload` utility with
585+
the `--finalize` option. The script will add GPG signatures to the
586+
`hashes` and `sha256sums` files and then upload the signed files:
587+
588+
```ShellSession
589+
$ script/upload --finalize vM.N.P
590+
```
591+
592+
18. Publish the release announcement.
593+
594+
19. Update the `_config.yml` file in the `git-lfs/git-lfs.github.com`
595+
repository with the new `M.N.P` release version and push the change,
596+
as described in the final steps of our standard release process.
597+
598+
In addition, update the `_includes/home/secondary.html` file with
599+
a banner message regarding the security PATCH release, and push
600+
the change.
601+
602+
20. Create a new discussion in the "Announcements" section of the GitHub
603+
discussion [forum](https://github.com/git-lfs/git-lfs/discussions)
604+
describing the security PATCH release, and pin the discussion for
605+
all categories in the forum.

0 commit comments

Comments
 (0)