Skip to content

Commit

Permalink
feat: generate sarif report using ansible-lint
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilippHeuer committed Nov 25, 2024
1 parent 1db8109 commit 6743152
Show file tree
Hide file tree
Showing 4 changed files with 293 additions and 5 deletions.
29 changes: 28 additions & 1 deletion actions/ansible/ansiblelint/ansible-lint.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package ansiblelint

import (
"fmt"
"path"

cidsdk "github.com/cidverse/cid-sdk-go"
"github.com/owenrumney/go-sarif/v2/sarif"
)

type Action struct {
Expand All @@ -20,6 +22,9 @@ func (a Action) Execute() (err error) {
return err
}

// files
reportFile := cidsdk.JoinPath(ctx.Config.TempDir, "ansiblelint.sarif.json")

// role and collection requirements
if a.Sdk.FileExists(path.Join(ctx.Module.ModuleDir, "requirements.yml")) {
_, err = a.Sdk.ExecuteCommand(cidsdk.ExecuteCommandRequest{
Expand All @@ -32,13 +37,35 @@ func (a Action) Execute() (err error) {
}

// lint
// config lookup: https://ansible.readthedocs.io/projects/lint/configuring/#using-local-configuration-files
_, err = a.Sdk.ExecuteCommand(cidsdk.ExecuteCommandRequest{
Command: `ansible-lint .`,
Command: fmt.Sprintf(`ansible-lint --project . --sarif-file %s`, reportFile),
WorkDir: ctx.Module.ModuleDir,
})
if err != nil {
return err
}

// parse report
reportContent, err := a.Sdk.FileRead(reportFile)
if err != nil {
return fmt.Errorf("failed to read report content from file %s: %s", reportFile, err.Error())
}
report, err := sarif.FromBytes([]byte(reportContent))
if err != nil {
return err
}

// store report
err = a.Sdk.ArtifactUpload(cidsdk.ArtifactUploadRequest{
File: reportFile,
Type: "report",
Format: "sarif",
FormatVersion: report.Version,
})
if err != nil {
return err
}

return nil
}
22 changes: 20 additions & 2 deletions actions/ansible/ansiblelint/ansible-lint_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ansiblelint

import (
_ "embed"
"testing"

"github.com/cidverse/cid-actions-go/actions/api"
Expand All @@ -10,14 +11,24 @@ import (
"github.com/stretchr/testify/mock"
)

//go:embed report.sarif.json
var reportJson string

func TestAnsibleLint(t *testing.T) {
sdk := test.Setup(t)
sdk.On("ModuleAction", mock.Anything).Return(api.GetAnsibleTestData(false), nil)
sdk.On("FileExists", "/my-project/playbook-a/requirements.yml").Return(false)
sdk.On("ExecuteCommand", cidsdk.ExecuteCommandRequest{
Command: "ansible-lint .",
Command: "ansible-lint --project . --sarif-file /my-project/.tmp/ansiblelint.sarif.json",
WorkDir: "/my-project/playbook-a",
}).Return(nil, nil)
sdk.On("FileRead", "/my-project/.tmp/ansiblelint.sarif.json").Return(reportJson, nil)
sdk.On("ArtifactUpload", cidsdk.ArtifactUploadRequest{
File: "/my-project/.tmp/ansiblelint.sarif.json",
Type: "report",
Format: "sarif",
FormatVersion: "2.1.0",
}).Return(nil)

action := Action{Sdk: sdk}
err := action.Execute()
Expand All @@ -33,9 +44,16 @@ func TestAnsibleLintWithDependencies(t *testing.T) {
WorkDir: "/my-project/playbook-a",
}).Return(nil, nil)
sdk.On("ExecuteCommand", cidsdk.ExecuteCommandRequest{
Command: "ansible-lint .",
Command: "ansible-lint --project . --sarif-file /my-project/.tmp/ansiblelint.sarif.json",
WorkDir: "/my-project/playbook-a",
}).Return(nil, nil)
sdk.On("FileRead", "/my-project/.tmp/ansiblelint.sarif.json").Return(reportJson, nil)
sdk.On("ArtifactUpload", cidsdk.ArtifactUploadRequest{
File: "/my-project/.tmp/ansiblelint.sarif.json",
Type: "report",
Format: "sarif",
FormatVersion: "2.1.0",
}).Return(nil)

action := Action{Sdk: sdk}
err := action.Execute()
Expand Down
242 changes: 242 additions & 0 deletions actions/ansible/ansiblelint/report.sarif.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
{
"$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json",
"version": "2.1.0",
"runs": [
{
"tool": {
"driver": {
"name": "ansible-lint",
"version": "24.9.2",
"informationUri": "https://github.com/ansible/ansible-lint",
"rules": [
{
"id": "name[play]",
"name": "name[play]",
"shortDescription": {
"text": "All plays should be named."
},
"defaultConfiguration": {
"level": "warning"
},
"help": {
"text": "All tasks and plays should have a distinct name for readability and for ``--start-at-task`` to work"
},
"helpUri": "https://ansible.readthedocs.io/projects/lint/rules/name/",
"properties": {
"tags": [
"idiom"
]
}
},
{
"id": "yaml[indentation]",
"name": "yaml[indentation]",
"shortDescription": {
"text": "Wrong indentation: expected at least 3"
},
"defaultConfiguration": {
"level": "warning"
},
"help": {
"text": ""
},
"helpUri": "https://ansible.readthedocs.io/projects/lint/rules/yaml/",
"properties": {
"tags": [
"formatting",
"yaml"
]
}
},
{
"id": "yaml[truthy]",
"name": "yaml[truthy]",
"shortDescription": {
"text": "Truthy value should be one of [false, true]"
},
"defaultConfiguration": {
"level": "warning"
},
"help": {
"text": ""
},
"helpUri": "https://ansible.readthedocs.io/projects/lint/rules/yaml/",
"properties": {
"tags": [
"formatting",
"yaml"
]
}
},
{
"id": "fqcn[action-core]",
"name": "fqcn[action-core]",
"shortDescription": {
"text": "Use FQCN for builtin module actions (command)."
},
"defaultConfiguration": {
"level": "warning"
},
"help": {
"text": "Check whether actions are using using full qualified collection names."
},
"helpUri": "https://ansible.readthedocs.io/projects/lint/rules/fqcn/",
"properties": {
"tags": [
"formatting"
]
}
},
{
"id": "yaml[trailing-spaces]",
"name": "yaml[trailing-spaces]",
"shortDescription": {
"text": "Trailing spaces"
},
"defaultConfiguration": {
"level": "warning"
},
"help": {
"text": ""
},
"helpUri": "https://ansible.readthedocs.io/projects/lint/rules/yaml/",
"properties": {
"tags": [
"formatting",
"yaml"
]
}
},
{
"id": "no-free-form",
"name": "no-free-form",
"shortDescription": {
"text": "Avoid using free-form when calling module actions. (yum)"
},
"defaultConfiguration": {
"level": "warning"
},
"help": {
"text": "Avoid free-form inside files as it can produce subtle bugs."
},
"helpUri": "https://ansible.readthedocs.io/projects/lint/rules/no-free-form/",
"properties": {
"tags": [
"syntax",
"risk"
]
}
},
{
"id": "syntax-check[unknown-module]",
"name": "syntax-check[unknown-module]",
"shortDescription": {
"text": "couldn't resolve module/action 'firewalld'. This often indicates a misspelling, missing collection, or incorrect module path."
},
"defaultConfiguration": {
"level": "error"
},
"help": {
"text": ""
},
"helpUri": "https://ansible.readthedocs.io/projects/lint/rules/syntax-check/",
"properties": {
"tags": [
"core",
"unskippable"
]
}
},
{
"id": "no-changed-when",
"name": "no-changed-when",
"shortDescription": {
"text": "Commands should not change things if nothing needs doing."
},
"defaultConfiguration": {
"level": "error"
},
"help": {
"text": ""
},
"helpUri": "https://ansible.readthedocs.io/projects/lint/rules/no-changed-when/",
"properties": {
"tags": [
"command-shell",
"idempotency"
]
}
},
{
"id": "risky-file-permissions",
"name": "risky-file-permissions",
"shortDescription": {
"text": "File permissions unset or incorrect."
},
"defaultConfiguration": {
"level": "error"
},
"help": {
"text": "Missing or unsupported mode parameter can cause unexpected file permissions based on version of Ansible being used. Be explicit, like `mode: 0644` to avoid hitting this rule. Special `preserve` value is accepted only by `copy`, `template` modules."
},
"helpUri": "https://ansible.readthedocs.io/projects/lint/rules/risky-file-permissions/",
"properties": {
"tags": [
"unpredictability"
]
}
},
{
"id": "yaml[line-length]",
"name": "yaml[line-length]",
"shortDescription": {
"text": "Line too long (170 > 160 characters)"
},
"defaultConfiguration": {
"level": "warning"
},
"help": {
"text": ""
},
"helpUri": "https://ansible.readthedocs.io/projects/lint/rules/yaml/",
"properties": {
"tags": [
"formatting",
"yaml"
]
}
}
]
}
},
"columnKind": "utf16CodeUnits",
"results": [
{
"ruleId": "yaml[line-length]",
"level": "error",
"message": {
"text": "Line too long (170 > 160 characters)"
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "roles/example/tasks/main.yml",
"uriBaseId": "SRCROOT"
},
"region": {
"startLine": 53
}
}
}
]
}
],
"originalUriBaseIds": {
"SRCROOT": {
"uri": "file:///my-project/"
}
}
}
]
}
5 changes: 3 additions & 2 deletions actions/api/testdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,9 @@ func GetAnsibleTestData(debug bool) cidsdk.ModuleActionData {
Config: cidsdk.CurrentConfig{
Debug: debug,
Log: map[string]string{},
ArtifactDir: ".dist",
TempDir: ".tmp",
ProjectDir: "/my-project",
ArtifactDir: "/my-project/.dist",
TempDir: "/my-project/.tmp",
},
}
}

0 comments on commit 6743152

Please sign in to comment.