@@ -337,3 +337,269 @@ and then use that branch as the base for the PATCH release.
337
337
338
338
5. Then follow the [guidelines](#building-a-release) above, using the
339
339
`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