Skip to content

Commit 32d2c7a

Browse files
[8.19] (backport #8124) Generate NOTICE-fips.txt file (#8136)
* Generate `NOTICE-fips.txt` file (#8124) * Amending code to generate NOTICE-fips.txt file alongside NOTICE.txt file * Adding generated NOTICE-fips.txt file * Adding CHANGELOG entry * Update dependabot workflow to also generate NOTICE-fips.txt file * Update notice target doc in Makefile * Update notice documentation in README * Cleanup * Override bundled NOTICE.txt with contents of NOTICE-fips.txt in FIPS-capable artifacts * Adding PR link to CHANGELOG entry * Adding NOTICE check to mage TestPackages workflow * Making comment consistent * Consolidate NOTICE check/update/commit steps (cherry picked from commit 2648f22) * Regenerating FIPS-notice.txt --------- Co-authored-by: Shaunak Kashyap <[email protected]>
1 parent 4b9f5d0 commit 32d2c7a

File tree

10 files changed

+79306
-45
lines changed

10 files changed

+79306
-45
lines changed

.github/workflows/post-dependabot.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Follow-on actions relating to dependabot PRs. In elastic/elastic-agent, any changes to
22
# dependencies contained in go.mod requires the change to be reflected in the
3-
# NOTICE.txt file. When dependabot creates a branch for a go_modules change this
4-
# will update the NOTICE.txt file for that change.
3+
# NOTICE.txt and NOTICE-fips.txt files. When dependabot creates a branch for a go_modules
4+
# change this will update the NOTICE.txt and NOTICE-fips files for that change.
55
name: post-dependabot
66

77
on:
@@ -26,26 +26,26 @@ jobs:
2626
with:
2727
install-only: true
2828

29-
- name: update NOTICE.txt
29+
- name: update NOTICE.txt and NOTICE-fips.txt
3030
run: make notice
3131

32-
- name: check for modified NOTICE.txt
32+
- name: check for modified NOTICE.txt or NOTICE-fips.txt
3333
id: notice-check
3434
run: |
35-
if git diff --quiet HEAD -- NOTICE.txt; then
35+
if git diff --quiet HEAD -- NOTICE*.txt; then
3636
echo "modified=false" >> $GITHUB_OUTPUT
3737
else
3838
echo "modified=true" >> $GITHUB_OUTPUT
3939
fi
4040
41-
- name: commit NOTICE.txt
41+
- name: commit NOTICE.txt and/or NOTICE-fips.txt
4242
if: steps.notice-check.outputs.modified == 'true'
4343
run: |
4444
git config --global user.name 'dependabot[bot]'
4545
git config --global user.email 'dependabot[bot]@users.noreply.github.com'
46-
git add NOTICE.txt
46+
git add NOTICE*.txt
4747
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
48-
git commit -m "Update NOTICE.txt"
48+
git commit -m "Update NOTICE.txt and/or NOTICE-fips.txt"
4949
git push
5050
5151
- name: update otel README.md

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ help: Makefile
1818
@printf "Variables:\n"
1919
@grep -E "^[A-Za-z0-9_]*\?=" $< | awk 'BEGIN {FS = "\\?="}; { printf " \033[36m%-25s\033[0m Default values: %s\n", $$1, $$2}'
2020

21-
## notice : Generates the NOTICE file.
21+
## notice : Generates the NOTICE.txt and NOTICE-fips.txt files.
2222
.PHONY: notice
2323
notice:
2424
@mage notice

NOTICE-fips.txt

Lines changed: 79156 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -258,12 +258,6 @@ rules implemented on our `Makefile` as well as CI will use the
258258
locally before submitting any PRs to have a quicker feedback instead
259259
of waiting for a CI failure.
260260

261-
### Generating the `NOTICE.txt` when updating/adding dependencies
262-
To do so, just run `make notice`, this is also part of the `make
261+
### Generating the `NOTICE.txt` and `NOTICE-fips.txt` when updating/adding dependencies
262+
To do so, just run `mage notice`, this is also part of the `make
263263
check-ci` and is the same check our CI will do.
264-
265-
At some point we will migrate it to mage (see discussion on
266-
https://github.com/elastic/elastic-agent/pull/1108 and on
267-
https://github.com/elastic/elastic-agent/issues/1107). However until
268-
we have the mage automation sorted out, it has been removed to avoid
269-
confusion.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Kind can be one of:
2+
# - breaking-change: a change to previously-documented behavior
3+
# - deprecation: functionality that is being removed in a later release
4+
# - bug-fix: fixes a problem in a previous version
5+
# - enhancement: extends functionality but does not break or fix existing behavior
6+
# - feature: new functionality
7+
# - known-issue: problems that we are aware of in a given version
8+
# - security: impacts on the security of a product or a user’s deployment.
9+
# - upgrade: important information for someone upgrading from a prior version
10+
# - other: does not fit into any of the other categories
11+
kind: other
12+
13+
# Change summary; a 80ish characters long description of the change.
14+
summary: A new NOTICE file, `NOTICE-fips.txt` is included in FIPS-capable Agent distributions.
15+
16+
# Long description; in case the summary is not enough to describe the change
17+
# this field accommodate a description without length limits.
18+
# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment.
19+
#description:
20+
21+
# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc.
22+
component: elastic-agent
23+
24+
# PR URL; optional; the PR number that added the changeset.
25+
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
26+
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
27+
# Please provide it if you are adding a fragment for a different PR.
28+
pr: https://github.com/elastic/elastic-agent/pull/8124
29+
30+
# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
31+
# If not present is automatically filled by the tooling with the issue linked to the PR number.
32+
#issue: https://github.com/owner/repo/1234

dev-tools/mage/pkg.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ func TestPackages(options ...TestPackagesOption) error {
267267
}
268268

269269
args = append(args, "-files", MustExpand("{{.PWD}}/build/distributions/*"))
270+
args = append(args, "--source-root", MustExpand("{{.PWD}}"))
270271

271272
if out, err := goTest(args...); err != nil {
272273
if mg.Verbose() {

dev-tools/mage/target/common/notice.go

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import (
1515
"slices"
1616
"strings"
1717

18+
"github.com/elastic/elastic-agent/dev-tools/notice"
19+
1820
"github.com/magefile/mage/sh"
1921
)
2022

@@ -28,17 +30,29 @@ func runCommand(cmd string, args ...string) error {
2830
return nil
2931
}
3032

31-
// Notice Generates NOTICE.txt.
33+
// Notice Generates NOTICE.txt and NOTICE-fips.txt
3234
func Notice() (err error) {
33-
fmt.Println("Generating NOTICE")
35+
if err := generateNotice(notice.NoticeFilename); err != nil {
36+
return fmt.Errorf("failed to generate %s: %w", notice.NoticeFilename, err)
37+
}
38+
if err := generateNotice(notice.FIPSNoticeFilename, "requirefips"); err != nil {
39+
return fmt.Errorf("failed to generate %s: %w", notice.FIPSNoticeFilename, err)
40+
}
41+
return nil
42+
}
43+
44+
// generateNotice generates a generateNotice file with the name outputFilename.
45+
// see getDependentModules for use of additionalTags.
46+
func generateNotice(outputFilename string, additionalTags ...string) error {
47+
fmt.Printf("Generating %s...\n", outputFilename)
3448
if err := runCommand("go", "mod", "tidy"); err != nil {
3549
return err
3650
}
3751
if err := runCommand("go", "mod", "download"); err != nil {
3852
return err
3953
}
4054

41-
modules, err := getDependentModules()
55+
modules, err := getDependentModules(additionalTags...)
4256
if err != nil {
4357
return fmt.Errorf("unable to fetch list of dependent modules: %w", err)
4458
}
@@ -52,7 +66,7 @@ func Notice() (err error) {
5266
// -rules dev-tools/notice/rules.json \
5367
// -overrides dev-tools/notice/overrides.json \
5468
// -noticeTemplate dev-tools/notice/NOTICE.txt.tmpl \
55-
// -noticeOut NOTICE.txt \
69+
// -noticeOut {outputFilename} \
5670
// -depsOut ""
5771
listCmdArgs := []string{"list", "-m", "-json"}
5872
listCmdArgs = append(listCmdArgs, modules...)
@@ -62,7 +76,7 @@ func Notice() (err error) {
6276
"-rules", "dev-tools/notice/rules.json",
6377
"-overrides", "dev-tools/notice/overrides.json",
6478
"-noticeTemplate", "dev-tools/notice/NOTICE.txt.tmpl",
65-
"-noticeOut", "NOTICE.txt",
79+
"-noticeOut", outputFilename,
6680
"-depsOut", "")
6781

6882
fmt.Printf(">> %s | %s\n", strings.Join(listCmd.Args, " "), strings.Join(licDetectCmd.Args, " "))
@@ -96,22 +110,21 @@ func Notice() (err error) {
96110
return err
97111
}
98112

99-
// cat dev-tools/notice/NOTICE.txt.append >> NOTICE.txt
100-
fmt.Printf(">> %s\n", "cat dev-tools/notice/NOTICE.txt.append >> NOTICE.txt")
113+
// cat dev-tools/notice/NOTICE.txt.append >> {outputFilename}
101114
const (
102-
infn = "dev-tools/notice/NOTICE.txt.append"
103-
outfn = "NOTICE.txt"
115+
infn = "dev-tools/notice/NOTICE.txt.append"
104116
)
117+
fmt.Printf(">> cat %s >> %s\n", infn, outputFilename)
105118

106119
f, err := os.Open(infn)
107120
if err != nil {
108121
return fmt.Errorf("failed to open file %s: %w", infn, err)
109122
}
110123
defer f.Close()
111124

112-
out, err := os.OpenFile(outfn, os.O_WRONLY|os.O_APPEND, 0644)
125+
out, err := os.OpenFile(outputFilename, os.O_WRONLY|os.O_APPEND, 0644)
113126
if err != nil {
114-
return fmt.Errorf("failed to open file %s: %w", outfn, err)
127+
return fmt.Errorf("failed to open file %s: %w", outputFilename, err)
115128
}
116129

117130
defer func() {
@@ -122,23 +135,23 @@ func Notice() (err error) {
122135
}()
123136

124137
if _, err := io.Copy(out, f); err != nil {
125-
return fmt.Errorf("failed to append file %s: %w", outfn, err)
138+
return fmt.Errorf("failed to append file %s: %w", outputFilename, err)
126139
}
127140

128-
// dos2unix NOTICE.txt
129-
fmt.Printf(">> %s\n", "dos2unix NOTICE.txt")
141+
// dos2unix {outputFilename}
142+
fmt.Printf(">> dos2unix %s\n", outputFilename)
130143

131-
content, err := os.ReadFile(outfn)
144+
content, err := os.ReadFile(outputFilename)
132145
if err != nil {
133-
return fmt.Errorf("failed to read entire file %s: %w", outfn, err)
146+
return fmt.Errorf("failed to read entire file %s: %w", outputFilename, err)
134147
}
135148

136149
// Convert Windows-style line endings to Unix-style
137150
newContent := strings.ReplaceAll(string(content), "\r\n", "\n")
138151

139-
err = os.WriteFile(outfn, []byte(newContent), 0644)
152+
err = os.WriteFile(outputFilename, []byte(newContent), 0644)
140153
if err != nil {
141-
return fmt.Errorf("failed to rewrite file using Unix-style line endings %s: %w", outfn, err)
154+
return fmt.Errorf("failed to rewrite file using Unix-style line endings %s: %w", outputFilename, err)
142155
}
143156

144157
return nil

dev-tools/notice/notice.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License 2.0;
3+
// you may not use this file except in compliance with the Elastic License 2.0.
4+
5+
package notice
6+
7+
const (
8+
NoticeFilename = "NOTICE.txt"
9+
FIPSNoticeFilename = "NOTICE-fips.txt"
10+
)

dev-tools/packaging/packages.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,10 @@ shared:
435435
files:
436436
<<: *agent_binary_files
437437
<<: *agent_unpacked_components_files
438+
NOTICE.txt:
439+
source: '{{ repo.RootDir }}/NOTICE-fips.txt'
440+
mode: 0644
441+
438442

439443
- &agent_darwin_binary_spec
440444
<<: *common

dev-tools/packaging/testing/package_test.go

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"github.com/stretchr/testify/require"
3737

3838
"github.com/elastic/elastic-agent/dev-tools/mage"
39+
"github.com/elastic/elastic-agent/dev-tools/notice"
3940
v1 "github.com/elastic/elastic-agent/pkg/api/v1"
4041
)
4142

@@ -65,6 +66,7 @@ var (
6566

6667
var (
6768
files = flag.String("files", "../build/distributions/*", "filepath glob containing package files")
69+
sourceRoot = flag.String("source-root", "../", "path to root directory of Agent repository")
6870
modules = flag.Bool("modules", false, "check modules folder contents")
6971
minModules = flag.Int("min-modules", 4, "minimum number of modules to expect in modules folder")
7072
modulesd = flag.Bool("modules.d", false, "check modules.d folder contents")
@@ -190,6 +192,7 @@ func checkTar(t *testing.T, file string, fipsCheck bool) {
190192
require.NoErrorf(t, err, "error extracting archive %q", file)
191193

192194
t.Run("check_manifest_file", testManifestFile(tempExtractionPath, fipsCheck))
195+
t.Run("check_notice_file", testNoticeFile(tempExtractionPath, fipsCheck))
193196

194197
checkSha512PackageHash(t, file)
195198

@@ -220,20 +223,31 @@ func checkZip(t *testing.T, file string) {
220223
require.NoErrorf(t, err, "error extracting archive %q", file)
221224

222225
t.Run("check_manifest_file", testManifestFile(tempExtractionPath, false))
226+
t.Run("check_notice_file", testNoticeFile(tempExtractionPath, false))
223227

224228
checkSha512PackageHash(t, file)
225229
}
226230

227231
func testManifestFile(agentPackageRootDir string, checkFips bool) func(t *testing.T) {
228232
return func(t *testing.T) {
229-
dirEntries, err := os.ReadDir(agentPackageRootDir)
230-
require.NoErrorf(t, err, "error listing extraction dir %q", agentPackageRootDir)
231-
require.Lenf(t, dirEntries, 1, "archive should contain a single directory: found %v", dirEntries)
232-
containingDir := dirEntries[0].Name()
233-
checkManifestFileContents(t, filepath.Join(agentPackageRootDir, containingDir))
233+
checkManifestFileContents(t, getExtractedPackageDir(agentPackageRootDir, t))
234234
}
235235
}
236236

237+
func testNoticeFile(agentPackageRootDir string, checkFips bool) func(t *testing.T) {
238+
return func(t *testing.T) {
239+
checkNoticeFileContents(t, getExtractedPackageDir(agentPackageRootDir, t), checkFips)
240+
}
241+
}
242+
243+
func getExtractedPackageDir(agentPackageRootDir string, t *testing.T) string {
244+
dirEntries, err := os.ReadDir(agentPackageRootDir)
245+
require.NoErrorf(t, err, "error listing extraction dir %q", agentPackageRootDir)
246+
require.Lenf(t, dirEntries, 1, "archive should contain a single directory: found %v", dirEntries)
247+
248+
return filepath.Join(agentPackageRootDir, dirEntries[0].Name())
249+
}
250+
237251
func checkManifestFileContents(t *testing.T, extractedPackageDir string) {
238252
t.Log("Checking file manifest.yaml")
239253
m := parseManifest(t, extractedPackageDir)
@@ -275,6 +289,47 @@ func parseManifest(t *testing.T, dir string) v1.PackageManifest {
275289
return *m
276290
}
277291

292+
func checkNoticeFileContents(t *testing.T, extractedPackageDir string, checkFips bool) {
293+
t.Logf("Checking package file NOTICE.txt; checkFips = %t", checkFips)
294+
295+
// Hash the source NOTICE file
296+
sourceNoticeFile := filepath.Join(*sourceRoot, notice.NoticeFilename)
297+
if checkFips {
298+
sourceNoticeFile = filepath.Join(*sourceRoot, notice.FIPSNoticeFilename)
299+
}
300+
sourceNoticeFile, err := filepath.Abs(sourceNoticeFile)
301+
require.NoError(t, err)
302+
303+
sourceNoticeFileHash, err := fileHash(sourceNoticeFile)
304+
require.NoError(t, err)
305+
306+
// Hash the NOTICE file in the package
307+
packageNoticeFile := filepath.Join(extractedPackageDir, "NOTICE.txt")
308+
packageNoticeFileHash, err := fileHash(packageNoticeFile)
309+
require.NoError(t, err)
310+
311+
// Compare the two hashes; they should be equal
312+
require.Equalf(
313+
t, sourceNoticeFileHash, packageNoticeFileHash,
314+
"Contents of NOTICE.txt file in package are not the same as contents of %s", sourceNoticeFile,
315+
)
316+
}
317+
318+
func fileHash(path string) ([]byte, error) {
319+
f, err := os.Open(path)
320+
if err != nil {
321+
return nil, err
322+
}
323+
defer f.Close()
324+
325+
h := sha512.New()
326+
if _, err := io.Copy(h, f); err != nil {
327+
return nil, err
328+
}
329+
330+
return h.Sum(nil), nil
331+
}
332+
278333
const (
279334
npcapLicense = `Dependency : Npcap \(https://nmap.org/npcap/\)`
280335
libpcapLicense = `Dependency : Libpcap \(http://www.tcpdump.org/\)`
@@ -621,11 +676,7 @@ func checkDockerUser(t *testing.T, p *packageFile, info *dockerInfo, expectRoot
621676
}
622677

623678
func checkFIPS(t *testing.T, agentPackageRootDir string) {
624-
dirEntries, err := os.ReadDir(agentPackageRootDir)
625-
require.NoErrorf(t, err, "error listing extraction dir %q", agentPackageRootDir)
626-
require.Lenf(t, dirEntries, 1, "archive should contain a single directory: found %v", dirEntries)
627-
628-
extractedPackageDir := filepath.Join(agentPackageRootDir, dirEntries[0].Name())
679+
extractedPackageDir := getExtractedPackageDir(agentPackageRootDir, t)
629680
t.Logf("Checking agent binary in %q for FIPS compliance", extractedPackageDir)
630681
m := parseManifest(t, extractedPackageDir)
631682
versionedHome := m.Package.VersionedHome

0 commit comments

Comments
 (0)