mirror of
https://github.com/fleetdm/fleet
synced 2026-05-09 18:20:48 +00:00
For #25090. # Checklist for submitter If some of the following don't apply, delete the relevant line. <!-- Note that API documentation changes are now addressed by the product design team. --> - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] Added/updated automated tests - [x] A detailed QA plan exists on the associated ticket (if it isn't there, work with the product group's QA engineer to add it) - [x] Manual QA for all new/changed functionality
122 lines
2.8 KiB
Go
122 lines
2.8 KiB
Go
package msrc
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/fleetdm/fleet/v4/pkg/fleethttp"
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
"github.com/fleetdm/fleet/v4/server/vulnerabilities/io"
|
|
"github.com/fleetdm/fleet/v4/server/vulnerabilities/msrc/parsed"
|
|
"github.com/google/go-github/v37/github"
|
|
)
|
|
|
|
// bulletinsDelta returns what bulletins should be downloaded from GH and what bulletins should be removed
|
|
// from the local file system based what OSes are installed, what local bulletins we have and what
|
|
// remote bulletins exist.
|
|
func bulletinsDelta(
|
|
os []fleet.OperatingSystem,
|
|
local []io.MetadataFileName,
|
|
remote []io.MetadataFileName,
|
|
) (
|
|
[]io.MetadataFileName,
|
|
[]io.MetadataFileName,
|
|
) {
|
|
if len(os) == 0 {
|
|
return remote, nil
|
|
}
|
|
|
|
var matching []io.MetadataFileName
|
|
for _, r := range remote {
|
|
for _, o := range os {
|
|
product := parsed.NewProductFromOS(o)
|
|
if r.ProductName() == product.Name() {
|
|
matching = append(matching, r)
|
|
}
|
|
}
|
|
}
|
|
|
|
downloadSet := map[io.MetadataFileName]struct{}{}
|
|
deleteSet := map[io.MetadataFileName]struct{}{}
|
|
for _, m := range matching {
|
|
var found bool
|
|
for _, l := range local {
|
|
if m.ProductName() == l.ProductName() {
|
|
found = true
|
|
// out of date
|
|
if l.Before(m) {
|
|
downloadSet[m] = struct{}{}
|
|
deleteSet[l] = struct{}{}
|
|
}
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
downloadSet[m] = struct{}{}
|
|
}
|
|
}
|
|
|
|
var toDownload []io.MetadataFileName
|
|
var toDelete []io.MetadataFileName
|
|
for filename := range downloadSet {
|
|
toDownload = append(toDownload, filename)
|
|
}
|
|
for filename := range deleteSet {
|
|
toDelete = append(toDelete, filename)
|
|
}
|
|
|
|
return toDownload, toDelete
|
|
}
|
|
|
|
// SyncFromGithub syncs the local msrc security bulletins (contained in dstDir) for one or more operating
|
|
// systems with the security bulletin published in Github.
|
|
//
|
|
// If 'os' is nil, then all security bulletins will be synched.
|
|
func SyncFromGithub(ctx context.Context, dstDir string, os []fleet.OperatingSystem) error {
|
|
client := fleethttp.NewGithubClient()
|
|
rep := github.NewClient(client).Repositories
|
|
gh := io.NewGitHubClient(client, rep, dstDir)
|
|
fs := io.NewFSClient(dstDir)
|
|
|
|
if err := sync(ctx, os, fs, gh); err != nil {
|
|
return fmt.Errorf("msrc sync: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func sync(
|
|
ctx context.Context,
|
|
os []fleet.OperatingSystem,
|
|
fsClient io.FSAPI,
|
|
ghClient io.GitHubAPI,
|
|
) error {
|
|
remoteURLs, err := ghClient.MSRCBulletins(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var remote []io.MetadataFileName
|
|
for r := range remoteURLs {
|
|
remote = append(remote, r)
|
|
}
|
|
|
|
local, err := fsClient.MSRCBulletins()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
toDownload, toDelete := bulletinsDelta(os, local, remote)
|
|
for _, b := range toDownload {
|
|
if _, err := ghClient.Download(remoteURLs[b]); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for _, d := range toDelete {
|
|
if err := fsClient.Delete(d); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|