Add new archive URL as data source for Mac Office release notes (#26978)

For #26977.

# 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
This commit is contained in:
Ian Littman 2025-03-10 08:46:18 -05:00 committed by GitHub
parent 20eb780ffd
commit b2efa09e2b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 52 additions and 25 deletions

View file

@ -0,0 +1 @@
* Added new (as of 2025-03-07) archives page to data source for MS Mac Office vulnerability feed (applies to vulnerabilities feed rather than a specific Fleet release).

View file

@ -2,7 +2,6 @@ package main
import (
"fmt"
"net/http"
"os"
"path/filepath"
"time"
@ -26,23 +25,10 @@ func main() {
panicif(err)
fmt.Println("Downloading and parsing Mac Office rel notes...")
res, err := http.Get(macoffice.RelNotesURL)
panicif(err)
defer res.Body.Close()
parsed, err := macoffice.ParseReleaseHTML(res.Body)
relNotes, err := macoffice.GetReleaseNotes(false)
panicif(err)
var relNotes macoffice.ReleaseNotes
for _, rn := range parsed {
// We only care about release notes that have a version set (because we need that for
// matching software entries) and also that contain some
// security updates (because we only intented to use the release notes for vulnerability processing).
if rn.Valid() {
relNotes = append(relNotes, rn)
}
}
err = relNotes.Serialize(time.Now(), outPath)
panicif(err)

View file

@ -45,5 +45,5 @@ func TestUp_20250127162751(t *testing.T) {
FROM information_schema.COLUMNS
WHERE collation_name != "utf8mb4_unicode_ci" AND table_schema = (SELECT database())`)
require.NoError(t, err)
require.Equal(t, []string{"secret", "node_key", "orbit_node_key", "name_bin"}, columns)
require.ElementsMatch(t, []string{"secret", "node_key", "orbit_node_key", "name_bin"}, columns)
}

View file

@ -1,7 +1,6 @@
package macoffice_test
import (
"net/http"
"testing"
"time"
@ -656,11 +655,7 @@ var expected = []macoffice.ReleaseNote{
func TestIntegrationsParseReleaseHTML(t *testing.T) {
nettest.Run(t)
res, err := http.Get(macoffice.RelNotesURL)
require.NoError(t, err)
defer res.Body.Close()
actual, err := macoffice.ParseReleaseHTML(res.Body)
actual, err := macoffice.GetReleaseNotes(true)
require.NoError(t, err)
require.NotEmpty(t, actual)

View file

@ -2,6 +2,7 @@ package macoffice
import (
"io"
"net/http"
"regexp"
"strings"
"time"
@ -33,6 +34,52 @@ var nameToType = map[string]ProductType{
"microsoft autoupdate": WholeSuite,
}
type releaseNotesURL string // type added to calm gosec variable URL warnings down
const (
primaryURL = releaseNotesURL("https://learn.microsoft.com/en-us/officeupdates/release-notes-office-for-mac")
archiveURL = releaseNotesURL("https://learn.microsoft.com/en-us/officeupdates/release-notes-office-for-mac-archived")
)
func GetReleaseNotes(includeInvalid bool) (ReleaseNotes, error) {
var relNotes ReleaseNotes
relNotes, err := addReleaseNotes(relNotes, primaryURL, includeInvalid)
if err != nil {
return nil, err
}
relNotes, err = addReleaseNotes(relNotes, archiveURL, includeInvalid)
if err != nil {
return nil, err
}
return relNotes, nil
}
func addReleaseNotes(relNotes ReleaseNotes, url releaseNotesURL, includeInvalid bool) (ReleaseNotes, error) {
res, err := http.Get(string(url))
if err != nil {
return nil, err
}
defer res.Body.Close()
parsed, err := parseReleaseHTML(res.Body)
if err != nil {
return nil, err
}
for _, rn := range parsed {
// Under normal operation (outside parser tests), we only care about release notes that have a version set
// (because we need that for matching software entries) and also that contain some
// security updates (because we only intend to use the release notes for vulnerability processing).
if includeInvalid || rn.Valid() {
relNotes = append(relNotes, rn)
}
}
return relNotes, nil
}
func parseRelDate(raw string) (time.Time, bool) {
layouts := []string{"January-2-2006", "January-2-2006-release", "January 2, 2006"}
for _, l := range layouts {
@ -70,7 +117,7 @@ func getId(token html.Token) string {
// ParseReleaseHTML parses the release page using the provided reader. It is assumed that elements
// in the page appear in order: first the release date then the version and finally any related
// security updates.
func ParseReleaseHTML(reader io.Reader) ([]ReleaseNote, error) {
func parseReleaseHTML(reader io.Reader) ([]ReleaseNote, error) {
var result []ReleaseNote
// We use these pieces of state to keep track of whether we are inside a 'Security Updates'

View file

@ -11,8 +11,6 @@ import (
"github.com/fleetdm/fleet/v4/server/vulnerabilities/utils"
)
const RelNotesURL = "https://learn.microsoft.com/en-us/officeupdates/release-notes-office-for-mac"
type ProductType int
const (