-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Set config file mode to 0600 in packages #3382
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package: github.com/elastic/beats/dev-tools | ||
import: [] | ||
testImports: | ||
- name: github.com/blakesmith/ar | ||
version: 8bd4349a67f2533b078dbc524689d15dba0f4659 | ||
- name: github.com/cavaliercoder/go-rpm | ||
version: 9664735b838ea0a81e4aace3197ebe0d4040f952 | ||
- name: golang.org/x/crypto | ||
version: 2f8be38b9a7533b8763d48273737ff6e90428a96 | ||
subpackages: | ||
- cast5 | ||
- openpgp | ||
- openpgp/armor | ||
- openpgp/elgamal | ||
- openpgp/errors | ||
- openpgp/packet | ||
- openpgp/s2k | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,289 @@ | ||
package dev_tools | ||
|
||
// This file contains tests that can be run on the generated packages. | ||
// To run these tests use `go test package_test.go`. | ||
|
||
import ( | ||
"archive/tar" | ||
"archive/zip" | ||
"bytes" | ||
"compress/gzip" | ||
"flag" | ||
"io" | ||
"os" | ||
"path/filepath" | ||
"regexp" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/blakesmith/ar" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we add a vendor directory to the dev-tools directory? I would prefer if we don't mix vendor packages for tools with actual libbeat / beats dependencies. This makes it easier to track where a dependency belongs to. Long term I'm thinking also to move dependencies which only belong to one beat into the beat if possible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I can move these to dev-tools. I was thinking about that when I added them because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I update the PR to move the dependencies to |
||
"github.com/cavaliercoder/go-rpm" | ||
) | ||
|
||
const ( | ||
expectedConfigMode = os.FileMode(0600) | ||
expectedConfigUID = 0 | ||
expectedConfigGID = 0 | ||
) | ||
|
||
var ( | ||
configFilePattern = regexp.MustCompile(`.*beat\.yml`) | ||
) | ||
|
||
var ( | ||
files = flag.String("files", "../build/upload/*/*", "filepath glob containing package files") | ||
) | ||
|
||
func TestRPM(t *testing.T) { | ||
rpms := getFiles(t, regexp.MustCompile(`\.rpm$`)) | ||
for _, rpm := range rpms { | ||
checkRPM(t, rpm) | ||
} | ||
} | ||
|
||
func TestDeb(t *testing.T) { | ||
debs := getFiles(t, regexp.MustCompile(`\.deb$`)) | ||
buf := new(bytes.Buffer) | ||
for _, deb := range debs { | ||
checkDeb(t, deb, buf) | ||
} | ||
} | ||
|
||
func TestTar(t *testing.T) { | ||
tars := getFiles(t, regexp.MustCompile(`\.tar\.gz$`)) | ||
for _, tar := range tars { | ||
checkTar(t, tar) | ||
} | ||
} | ||
|
||
func TestZip(t *testing.T) { | ||
zips := getFiles(t, regexp.MustCompile(`^\w+beat-\S+.zip$`)) | ||
for _, zip := range zips { | ||
checkZip(t, zip) | ||
} | ||
} | ||
|
||
// Sub-tests | ||
|
||
func checkRPM(t *testing.T, file string) { | ||
p, err := readRPM(file) | ||
if err != nil { | ||
t.Error(err) | ||
return | ||
} | ||
|
||
checkConfigPermissions(t, p) | ||
} | ||
|
||
func checkDeb(t *testing.T, file string, buf *bytes.Buffer) { | ||
p, err := readDeb(file, buf) | ||
if err != nil { | ||
t.Error(err) | ||
return | ||
} | ||
|
||
checkConfigPermissions(t, p) | ||
checkConfigOwner(t, p) | ||
} | ||
|
||
func checkTar(t *testing.T, file string) { | ||
p, err := readTar(file) | ||
if err != nil { | ||
t.Error(err) | ||
return | ||
} | ||
|
||
checkConfigPermissions(t, p) | ||
checkConfigOwner(t, p) | ||
} | ||
|
||
func checkZip(t *testing.T, file string) { | ||
p, err := readZip(file) | ||
if err != nil { | ||
t.Error(err) | ||
return | ||
} | ||
|
||
checkConfigPermissions(t, p) | ||
} | ||
|
||
// Verify that the main configuration file is installed with a 0600 file mode. | ||
func checkConfigPermissions(t *testing.T, p *packageFile) { | ||
t.Run(p.Name+" config file permissions", func(t *testing.T) { | ||
for _, entry := range p.Contents { | ||
if configFilePattern.MatchString(entry.File) { | ||
mode := entry.Mode.Perm() | ||
if expectedConfigMode != mode { | ||
t.Errorf("file %v has wrong permissions: expected=%v actual=%v", | ||
entry.Mode, expectedConfigMode, mode) | ||
} | ||
return | ||
} | ||
} | ||
t.Errorf("no config file found matching %v", configFilePattern) | ||
}) | ||
} | ||
|
||
func checkConfigOwner(t *testing.T, p *packageFile) { | ||
t.Run(p.Name+" config file owner", func(t *testing.T) { | ||
for _, entry := range p.Contents { | ||
if configFilePattern.MatchString(entry.File) { | ||
if expectedConfigUID != entry.UID { | ||
t.Errorf("file %v should be owned by user %v, owner=%v", entry.File, expectedConfigGID, entry.UID) | ||
} | ||
if expectedConfigGID != entry.GID { | ||
t.Errorf("file %v should be owned by group %v, group=%v", entry.File, expectedConfigGID, entry.GID) | ||
} | ||
return | ||
} | ||
} | ||
t.Errorf("no config file found matching %v", configFilePattern) | ||
}) | ||
} | ||
|
||
// Helpers | ||
|
||
type packageFile struct { | ||
Name string | ||
Contents map[string]packageEntry | ||
} | ||
|
||
type packageEntry struct { | ||
File string | ||
UID int | ||
GID int | ||
Mode os.FileMode | ||
} | ||
|
||
func getFiles(t *testing.T, pattern *regexp.Regexp) []string { | ||
matches, err := filepath.Glob(*files) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
files := matches[:0] | ||
for _, f := range matches { | ||
if pattern.MatchString(filepath.Base(f)) { | ||
files = append(files, f) | ||
} | ||
} | ||
|
||
return files | ||
} | ||
|
||
func readRPM(rpmFile string) (*packageFile, error) { | ||
p, err := rpm.OpenPackageFile(rpmFile) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
contents := p.Files() | ||
pf := &packageFile{Name: filepath.Base(rpmFile), Contents: map[string]packageEntry{}} | ||
|
||
for _, file := range contents { | ||
pf.Contents[file.Name()] = packageEntry{ | ||
File: file.Name(), | ||
Mode: file.Mode(), | ||
} | ||
} | ||
|
||
return pf, nil | ||
} | ||
|
||
// readDeb reads the data.tar.gz file from the .deb. | ||
func readDeb(debFile string, dataBuffer *bytes.Buffer) (*packageFile, error) { | ||
file, err := os.Open(debFile) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer file.Close() | ||
|
||
arReader := ar.NewReader(file) | ||
for { | ||
header, err := arReader.Next() | ||
if err != nil { | ||
if err == io.EOF { | ||
break | ||
} | ||
return nil, err | ||
} | ||
|
||
if strings.HasPrefix(header.Name, "data.tar.gz") { | ||
dataBuffer.Reset() | ||
_, err := io.Copy(dataBuffer, arReader) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
gz, err := gzip.NewReader(dataBuffer) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer gz.Close() | ||
|
||
return readTarContents(filepath.Base(debFile), gz) | ||
} | ||
} | ||
|
||
return nil, io.EOF | ||
} | ||
|
||
func readTar(tarFile string) (*packageFile, error) { | ||
file, err := os.Open(tarFile) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer file.Close() | ||
|
||
var fileReader io.ReadCloser = file | ||
if strings.HasSuffix(tarFile, ".gz") { | ||
if fileReader, err = gzip.NewReader(file); err != nil { | ||
return nil, err | ||
} | ||
defer fileReader.Close() | ||
} | ||
|
||
return readTarContents(filepath.Base(tarFile), fileReader) | ||
} | ||
|
||
func readTarContents(tarName string, data io.Reader) (*packageFile, error) { | ||
tarReader := tar.NewReader(data) | ||
|
||
p := &packageFile{Name: tarName, Contents: map[string]packageEntry{}} | ||
for { | ||
header, err := tarReader.Next() | ||
if err != nil { | ||
if err == io.EOF { | ||
break | ||
} | ||
return nil, err | ||
} | ||
|
||
p.Contents[header.Name] = packageEntry{ | ||
File: header.Name, | ||
UID: header.Uid, | ||
GID: header.Gid, | ||
Mode: os.FileMode(header.Mode), | ||
} | ||
} | ||
|
||
return p, nil | ||
} | ||
|
||
func readZip(zipFile string) (*packageFile, error) { | ||
r, err := zip.OpenReader(zipFile) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer r.Close() | ||
|
||
p := &packageFile{Name: filepath.Base(zipFile), Contents: map[string]packageEntry{}} | ||
for _, f := range r.File { | ||
p.Contents[f.Name] = packageEntry{ | ||
File: f.Name, | ||
Mode: f.Mode(), | ||
} | ||
} | ||
|
||
return p, nil | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wasn't aware of this glide feature.