diff --git a/docs/goss.yaml b/docs/goss.yaml index a155c67d..2d3bdb63 100644 --- a/docs/goss.yaml +++ b/docs/goss.yaml @@ -40,6 +40,7 @@ file: sha512: cb71b1940dc879a3688bd502846bff6316dd537bbe917484964fe0f098e9245d80958258dc3bd6297bf42d5bd978cbe2c03d077d4ed45b2b1ed9cd831ceb1bd0 linked-to: /usr/sbin/sendmail.sendmail skip: false + capabilities: [] # Inline templates are not valid json/yaml that could be validated as-in by json schema # Instead, run `goss --vars ./vars.yaml render > rendered_goss.yaml` to render them # and apply the schema validation on the rendered file. @@ -153,7 +154,7 @@ package: versions: - "2.1" skip: false -# https://github.com/goss-org/goss/blob/master/README.md#manually-editing-goss-files +# https://github.com/goss-org/goss/blob/master/README.md#manually-editing-goss-files kernel: installed: true versions: diff --git a/docs/gossfile.md b/docs/gossfile.md index a463c2ce..c095e791 100644 --- a/docs/gossfile.md +++ b/docs/gossfile.md @@ -274,6 +274,9 @@ file: filetype: symlink # file, symlink, directory, socket linked-to: /usr/sbin/sendmail.sendmail skip: false + capabilities: + - 38 # CAP_PERFMON https://github.com/syndtr/gocapability/blob/master/capability/enum.go#L268 + - 21 # CAP_SYS_ADMIN https://github.com/syndtr/gocapability/blob/master/capability/enum.go#L193 ``` `contents` can be a string or a [pattern](#patterns) diff --git a/docs/platforms.md b/docs/platforms.md index 340859d5..2b78db97 100644 --- a/docs/platforms.md +++ b/docs/platforms.md @@ -75,6 +75,7 @@ This matrix attempts to track parity across platforms. | | md5 | {{ fully_supported }} | {{ work_partially }} | {{ work_partially }} | | | sha256 | {{ fully_supported }} | {{ work_partially }} | {{ work_partially }} | | | linked-to | {{ fully_supported }} | {{ no_data }} | {{ no_data }} | +| | capabilities | {{ fully_supported }} | {{ no_data }} | {{ no_data }} | | **gossfile** | | {{ fully_supported }} | {{ work_partially }} | {{ work_partially }} | | **group** | | {{ fully_supported }} | {{ not_implemented }} | {{ not_implemented }} | | | exists | {{ fully_supported }} | {{ not_implemented }} | {{ not_implemented }} | diff --git a/docs/rendered_goss.yaml b/docs/rendered_goss.yaml index 9a57afa7..b86ee68b 100644 --- a/docs/rendered_goss.yaml +++ b/docs/rendered_goss.yaml @@ -12,6 +12,7 @@ file: md5: 7c9bb14b3bf178e82c00c2a4398c93cd sha256: 7f78ce27859049f725936f7b52c6e25d774012947d915e7b394402cfceb70c4c sha512: cb71b1940dc879a3688bd502846bff6316dd537bbe917484964fe0f098e9245d80958258dc3bd6297bf42d5bd978cbe2c03d077d4ed45b2b1ed9cd831ceb1bd0 + capabilities: [] /etc/group: exists: true mode: "0644" diff --git a/docs/schema.yaml b/docs/schema.yaml index 661ae527..d98ee33e 100644 --- a/docs/schema.yaml +++ b/docs/schema.yaml @@ -150,6 +150,12 @@ definitions: skip: type: boolean default: false + capabilities: + type: array + items: + type: string + default: [] + description: Linux capabilities gossfileTest: properties: title: { "$ref":"#/definitions/title" } diff --git a/go.mod b/go.mod index b0375c1e..21269e3c 100644 --- a/go.mod +++ b/go.mod @@ -48,6 +48,7 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/spf13/cast v1.7.0 // indirect + github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect golang.org/x/crypto v0.26.0 // indirect diff --git a/go.sum b/go.sum index f1b3a22a..523ec569 100644 --- a/go.sum +++ b/go.sum @@ -101,6 +101,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= diff --git a/resource/file.go b/resource/file.go index 6b3c94c4..50b0607f 100644 --- a/resource/file.go +++ b/resource/file.go @@ -10,25 +10,26 @@ import ( ) type File struct { - Title string `json:"title,omitempty" yaml:"title,omitempty"` - Meta meta `json:"meta,omitempty" yaml:"meta,omitempty"` - id string `json:"-" yaml:"-"` - Path string `json:"path,omitempty" yaml:"path,omitempty"` - Exists matcher `json:"exists" yaml:"exists"` - Mode matcher `json:"mode,omitempty" yaml:"mode,omitempty"` - Size matcher `json:"size,omitempty" yaml:"size,omitempty"` - Owner matcher `json:"owner,omitempty" yaml:"owner,omitempty"` - Uid matcher `json:"uid,omitempty" yaml:"uid,omitempty"` - Group matcher `json:"group,omitempty" yaml:"group,omitempty"` - Gid matcher `json:"gid,omitempty" yaml:"gid,omitempty"` - LinkedTo matcher `json:"linked-to,omitempty" yaml:"linked-to,omitempty"` - Filetype matcher `json:"filetype,omitempty" yaml:"filetype,omitempty"` - Contains matcher `json:"contains,omitempty" yaml:"contains,omitempty"` - Contents matcher `json:"contents" yaml:"contents"` - Md5 matcher `json:"md5,omitempty" yaml:"md5,omitempty"` - Sha256 matcher `json:"sha256,omitempty" yaml:"sha256,omitempty"` - Sha512 matcher `json:"sha512,omitempty" yaml:"sha512,omitempty"` - Skip bool `json:"skip,omitempty" yaml:"skip,omitempty"` + Title string `json:"title,omitempty" yaml:"title,omitempty"` + Meta meta `json:"meta,omitempty" yaml:"meta,omitempty"` + id string `json:"-" yaml:"-"` + Path string `json:"path,omitempty" yaml:"path,omitempty"` + Exists matcher `json:"exists" yaml:"exists"` + Mode matcher `json:"mode,omitempty" yaml:"mode,omitempty"` + Size matcher `json:"size,omitempty" yaml:"size,omitempty"` + Owner matcher `json:"owner,omitempty" yaml:"owner,omitempty"` + Uid matcher `json:"uid,omitempty" yaml:"uid,omitempty"` + Group matcher `json:"group,omitempty" yaml:"group,omitempty"` + Gid matcher `json:"gid,omitempty" yaml:"gid,omitempty"` + LinkedTo matcher `json:"linked-to,omitempty" yaml:"linked-to,omitempty"` + Filetype matcher `json:"filetype,omitempty" yaml:"filetype,omitempty"` + Contains matcher `json:"contains,omitempty" yaml:"contains,omitempty"` + Contents matcher `json:"contents" yaml:"contents"` + Md5 matcher `json:"md5,omitempty" yaml:"md5,omitempty"` + Sha256 matcher `json:"sha256,omitempty" yaml:"sha256,omitempty"` + Sha512 matcher `json:"sha512,omitempty" yaml:"sha512,omitempty"` + Skip bool `json:"skip,omitempty" yaml:"skip,omitempty"` + Capabilities matcher `json:"capabilities,omitempty" yaml:"capabilities,omitempty"` } const ( @@ -110,6 +111,9 @@ func (f *File) Validate(sys *system.System) []TestResult { if f.Sha512 != nil { results = append(results, ValidateValue(f, "sha512", f.Sha512, sysFile.Sha512, skip)) } + if f.Capabilities != nil { + results = append(results, ValidateValue(f, "capabilities", f.Capabilities, sysFile.Capabilities, skip)) + } return results } diff --git a/system/file.go b/system/file.go index a6f1efae..15877c4d 100644 --- a/system/file.go +++ b/system/file.go @@ -6,6 +6,7 @@ import ( "crypto/sha256" "crypto/sha512" "fmt" + "github.com/syndtr/gocapability/capability" "hash" "io" "os" @@ -32,6 +33,7 @@ type File interface { Md5() (string, error) Sha256() (string, error) Sha512() (string, error) + Capabilities() ([]string, error) } type hashFuncType string @@ -97,6 +99,28 @@ func (f *DefFile) Contents() (io.Reader, error) { return fh, nil } +func (f *DefFile) Capabilities() ([]string, error) { + if err := f.setup(); err != nil { + return nil, err + } + + fileCaps, err := capability.NewFile2(f.realPath) + if err != nil { + return nil, err + } + if err = fileCaps.Load(); err != nil { + return nil, err + } + + var effectiveCaps []string + for _, c := range capability.List() { + if fileCaps.Get(capability.EFFECTIVE, c) { + effectiveCaps = append(effectiveCaps, strconv.Itoa(int(c))) + } + } + return effectiveCaps, nil +} + func (f *DefFile) Size() (int, error) { if err := f.setup(); err != nil { return 0, err