diff --git a/go.mod b/go.mod index 0f9c3a4..96d4e6c 100644 --- a/go.mod +++ b/go.mod @@ -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 @@ -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 @@ -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 diff --git a/go.sum b/go.sum index 2edb8aa..5c95b58 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/main.go b/main.go index 67f3908..357a535 100644 --- a/main.go +++ b/main.go @@ -21,7 +21,6 @@ import ( type AptVersion struct { logger hclog.Logger - data map[string]interface{} config map[string]string } @@ -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. @@ -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{