Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ module github.com/compliance-framework/plugin-apt-versions
go 1.23.2

require (
github.com/compliance-framework/agent v0.0.13
github.com/compliance-framework/agent v0.0.15
github.com/compliance-framework/configuration-service v0.0.5
github.com/golang/protobuf v1.5.4
github.com/google/uuid v1.6.0
github.com/hashicorp/go-hclog v1.5.0
Expand All @@ -16,7 +17,6 @@ require (
github.com/agnivade/levenshtein v1.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/compliance-framework/configuration-service v0.0.3 // indirect
github.com/defenseunicorns/go-oscal v0.6.2 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/go-ini/ini v1.67.0 // indirect
Expand All @@ -41,7 +41,6 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/yashtewari/glob-intersection v0.2.0 // indirect
go.mongodb.org/mongo-driver v1.17.2 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel v1.33.0 // indirect
go.opentelemetry.io/otel/metric v1.33.0 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/compliance-framework/agent v0.0.13 h1:4lz667PUbDUGiJx/9AXKuO9BVotXTnaMGvGe/euG4lg=
github.com/compliance-framework/agent v0.0.13/go.mod h1:Op7+BLJ2Rze9bh/jqWt81GnsUKIczP/IBduGZXE81BQ=
github.com/compliance-framework/configuration-service v0.0.3 h1:aeC1UN8uG4oxfphOWZeWJAmnUPBg863e/UaR0rCiPdM=
github.com/compliance-framework/configuration-service v0.0.3/go.mod h1:irXS+U+ZGaNrOmaNqb+pMmo+4BxSZJ0/vs4ne/5qVJc=
github.com/compliance-framework/agent v0.0.15 h1:VEB3xI3VSgTeudw8L+Czv9VCMt6vM7Nutd+JeMjWjuk=
github.com/compliance-framework/agent v0.0.15/go.mod h1:/ZxHkJJm/wthxm+W7atUgSMfL2217cCaBgN6dfsDSYo=
github.com/compliance-framework/configuration-service v0.0.5 h1:vK9mSb8dzaaTt+hd+g2g3+8nvfr/Ha5pMXB4yiYMA64=
github.com/compliance-framework/configuration-service v0.0.5/go.mod h1:irXS+U+ZGaNrOmaNqb+pMmo+4BxSZJ0/vs4ne/5qVJc=
github.com/containerd/containerd v1.7.24 h1:zxszGrGjrra1yYJW/6rhm9cJ1ZQ8rkKBR48brqsa7nA=
github.com/containerd/containerd v1.7.24/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
Expand Down
214 changes: 100 additions & 114 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (

type AptVersion struct {
logger hclog.Logger
data map[string]interface{}
config map[string]string
}

Expand Down Expand Up @@ -122,27 +121,6 @@ func GetInstalledPackages(l *AptVersion) (map[string]interface{}, string, error)
return packages, output, nil
}

func (l *AptVersion) PrepareForEval(req *proto.PrepareForEvalRequest) (*proto.PrepareForEvalResponse, error) {

// PrepareForEval is called once on every scheduled plugin execution.
// Here you should collect the data that should be evaluated with policies or checks.
// You should not make any observations or findings here. Only collect the data you need for policy / compliance checks.

// This method does most of the heavy lifting for your plugin.
// Here are a few examples of when it will be used:
// Local SSH Plugin: Fetch the SSH configuration from the local machine
// SAST Report Plugin: Convert a SAST sarif report into a usable structure for policies to be written against
// Azure VM Label Plugin: Collect all the VMs from the Azure API so they can be evaluated against policies

data, output, err := GetInstalledPackages(l)
l.logger.Debug(fmt.Sprintf("JSON OUTPUT 0.1.6: %s", output))
if err != nil {
return nil, fmt.Errorf("error getting installed packages: %w", err)
}
l.data = data
return &proto.PrepareForEvalResponse{}, nil
}

func (l *AptVersion) Eval(request *proto.EvalRequest, apiHelper runner.ApiHelper) (*proto.EvalResponse, error) {

// Eval is used to run policies against the data you've collected in PrepareForEval.
Expand All @@ -155,117 +133,125 @@ func (l *AptVersion) Eval(request *proto.EvalRequest, apiHelper runner.ApiHelper
ctx := context.TODO()
startTime := time.Now()

// The Policy Manager aggregates much of the policy execution and output structuring.
results, err := policyManager.
New(ctx, l.logger, request.GetBundlePath()).
Execute(ctx, "apt_version", l.data)

data, output, err := GetInstalledPackages(l)
l.logger.Debug(fmt.Sprintf("JSON OUTPUT 0.1.6: %s", output))
if err != nil {
l.logger.Error("Failed to evaluate against policy bundle", "error", err)
return &proto.EvalResponse{
Status: proto.ExecutionStatus_FAILURE,
}, err
return nil, fmt.Errorf("error getting installed packages: %w", err)
}

hostname := os.Getenv("HOSTNAME")

response := runner.NewCallableAssessmentResult()
response.Title = fmt.Sprintf("Package Version compliance for host: %s", hostname)

for _, policyResult := range results {

// There are no violations reported from the policies.
// We'll send the observation back to the agent
if len(policyResult.Violations) == 0 {
response.AddObservation(&proto.Observation{
Uuid: uuid.New().String(),
Title: protolang.String("The plugin succeeded. No compliance issues to report."),
Description: "The plugin policies did not return any violations. The configuration is in compliance with policies.",
Collected: timestamppb.New(time.Now()),
Expires: timestamppb.New(time.Now().AddDate(0, 1, 0)), // Add one month for the expiration
RelevantEvidence: []*proto.RelevantEvidence{
{
Description: fmt.Sprintf("Policy %v was evaluated, and no violations were found on machineId: %s", policyResult.Policy.Package.PurePackage(), "ARN:12345"),
},
},
})

response.AddFinding(&proto.Finding{
Title: fmt.Sprintf("No violations found on %s", policyResult.Policy.Package.PurePackage()),
Description: fmt.Sprintf("No violations found on the %s policy within the Apt Versions Plugin.", policyResult.Policy.Package.PurePackage()),
Target: &proto.FindingTarget{
Status: &proto.ObjectiveStatus{
State: runner.FindingTargetStatusSatisfied,
},
},
})
for _, policyPath := range request.GetPolicyPaths() {
// The Policy Manager aggregates much of the policy execution and output structuring.
results, err := policyManager.
New(ctx, l.logger, policyPath).
Execute(ctx, "apt_version", data)

if err != nil {
l.logger.Error("Failed to evaluate against policy bundle", "error", err)
return &proto.EvalResponse{
Status: proto.ExecutionStatus_FAILURE,
}, err
}

// There are violations in the policy checks.
// We'll send these observations back to the agent
if len(policyResult.Violations) > 0 {
observation := &proto.Observation{
Uuid: uuid.New().String(),
Title: protolang.String(fmt.Sprintf("The plugin found violations for policy %s on machineId: %s", policyResult.Policy.Package.PurePackage(), "ARN:12345")),
Description: fmt.Sprintf("Observed %d violation(s) for policy %s within the Plugin on machineId: %s.", len(policyResult.Violations), policyResult.Policy.Package.PurePackage(), "ARN:12345"),
Collected: timestamppb.New(time.Now()),
Expires: timestamppb.New(time.Now().AddDate(0, 1, 0)), // Add one month for the expiration
RelevantEvidence: []*proto.RelevantEvidence{
{
Description: fmt.Sprintf("Policy %v was evaluated, and %d violations were found on machineId: %s", policyResult.Policy.Package.PurePackage(), len(policyResult.Violations), "ARN:12345"),
},
},
}
response.AddObservation(observation)
hostname := os.Getenv("HOSTNAME")

for _, violation := range policyResult.Violations {
response.AddFinding(&proto.Finding{
response := runner.NewCallableAssessmentResult()
response.Title = fmt.Sprintf("Package Version compliance for host: %s", hostname)

for _, policyResult := range results {

// There are no violations reported from the policies.
// We'll send the observation back to the agent
if len(policyResult.Violations) == 0 {
response.AddObservation(&proto.Observation{
Uuid: uuid.New().String(),
Title: violation.Title,
Description: violation.Description,
Remarks: protolang.String(violation.Remarks),
RelatedObservations: []*proto.RelatedObservation{
Title: protolang.String("The plugin succeeded. No compliance issues to report."),
Description: "The plugin policies did not return any violations. The configuration is in compliance with policies.",
Collected: timestamppb.New(time.Now()),
Expires: timestamppb.New(time.Now().AddDate(0, 1, 0)), // Add one month for the expiration
RelevantEvidence: []*proto.RelevantEvidence{
{
ObservationUuid: observation.Uuid,
Description: fmt.Sprintf("Policy %v was evaluated, and no violations were found on machineId: %s", policyResult.Policy.Package.PurePackage(), "ARN:12345"),
},
},
})

response.AddFinding(&proto.Finding{
Title: fmt.Sprintf("No violations found on %s", policyResult.Policy.Package.PurePackage()),
Description: fmt.Sprintf("No violations found on the %s policy within the Apt Versions Plugin.", policyResult.Policy.Package.PurePackage()),
Target: &proto.FindingTarget{
Status: &proto.ObjectiveStatus{
State: runner.FindingTargetStatusNotSatisfied,
State: runner.FindingTargetStatusSatisfied,
},
},
})
}

}
}
// There are violations in the policy checks.
// We'll send these observations back to the agent
if len(policyResult.Violations) > 0 {
observation := &proto.Observation{
Uuid: uuid.New().String(),
Title: protolang.String(fmt.Sprintf("The plugin found violations for policy %s on machineId: %s", policyResult.Policy.Package.PurePackage(), "ARN:12345")),
Description: fmt.Sprintf("Observed %d violation(s) for policy %s within the Plugin on machineId: %s.", len(policyResult.Violations), policyResult.Policy.Package.PurePackage(), "ARN:12345"),
Collected: timestamppb.New(time.Now()),
Expires: timestamppb.New(time.Now().AddDate(0, 1, 0)), // Add one month for the expiration
RelevantEvidence: []*proto.RelevantEvidence{
{
Description: fmt.Sprintf("Policy %v was evaluated, and %d violations were found on machineId: %s", policyResult.Policy.Package.PurePackage(), len(policyResult.Violations), "ARN:12345"),
},
},
}
response.AddObservation(observation)

for _, violation := range policyResult.Violations {
response.AddFinding(&proto.Finding{
Uuid: uuid.New().String(),
Title: violation.Title,
Description: violation.Description,
Remarks: protolang.String(violation.Remarks),
RelatedObservations: []*proto.RelatedObservation{
{
ObservationUuid: observation.Uuid,
},
},
Target: &proto.FindingTarget{
Status: &proto.ObjectiveStatus{
State: runner.FindingTargetStatusNotSatisfied,
},
},
})
}

endTime := time.Now()
response.Start = timestamppb.New(startTime)
response.End = timestamppb.New(endTime)
response.AddLogEntry(&proto.AssessmentLog_Entry{
Title: protolang.String("Plugin checks completed"),
Start: timestamppb.New(startTime),
End: timestamppb.New(endTime),
})
}
}

streamId, err := sdk.SeededUUID(map[string]string{
"type": "apt-versions",
"_hostname": hostname,
"_policy": request.GetBundlePath(),
})
if err != nil {
return nil, err
}
if err := apiHelper.CreateResult(streamId.String(), map[string]string{
"type": "apt-versions",
"_hostname": hostname,
"_policy": request.GetBundlePath(),
}, response.Result()); err != nil {
l.logger.Error("Failed to add assessment result", "error", err)
return &proto.EvalResponse{
Status: proto.ExecutionStatus_FAILURE,
}, err
endTime := time.Now()
response.Start = timestamppb.New(startTime)
response.End = timestamppb.New(endTime)
response.AddLogEntry(&proto.AssessmentLog_Entry{
Title: protolang.String("Plugin checks completed"),
Start: timestamppb.New(startTime),
End: timestamppb.New(endTime),
})

streamId, err := sdk.SeededUUID(map[string]string{
"type": "apt-versions",
"_hostname": hostname,
"_policy": policyPath,
})
if err != nil {
return nil, err
}
if err := apiHelper.CreateResult(streamId.String(), map[string]string{
"type": "apt-versions",
"_hostname": hostname,
"_policy": policyPath,
}, policyPath, response.Result()); err != nil {
l.logger.Error("Failed to add assessment result", "error", err)
return &proto.EvalResponse{
Status: proto.ExecutionStatus_FAILURE,
}, err
}
}

return &proto.EvalResponse{
Expand Down
Loading