From d8eb84e68c5760fca81ef9acece0d81ad76b9f0e Mon Sep 17 00:00:00 2001 From: Takumi Yanagawa <113283236+yana1205@users.noreply.github.com> Date: Thu, 2 May 2024 17:11:17 +0900 Subject: [PATCH] Move to Python project for easily to leverage Trestle (#10) * move go project to go/ Signed-off-by: Takumi Yanagawa * update makefile to build cp2cli as submodule Signed-off-by: Takumi Yanagawa * update docs for url changes Signed-off-by: Takumi Yanagawa * import c2p python project Signed-off-by: Takumi Yanagawa * update README.md for message of deprecating C2P in Go Signed-off-by: Takumi Yanagawa * add Code of Conduct, Contributor guide, and maintainers list Signed-off-by: Takumi Yanagawa * update go/README.md release guide Signed-off-by: Takumi Yanagawa --------- Signed-off-by: Takumi Yanagawa --- .../create-and-publish-image.yml | 0 .../goreleaser-workflow.yml | 0 .gitignore | 183 ++- .pre-commit-config.yaml | 21 + .secrets.baseline | 152 ++ CODE_OF_CONDUCT.md | 3 + CONTRIBUTING.md | 186 +++ MAINTAINERS.md | 5 + Makefile | 318 +--- README.md | 307 +++- c2p/__init__.py | 15 + c2p/__main__.py | 26 + c2p/cli.py | 53 + c2p/commands/__init__.py | 15 + c2p/commands/tools/__init__.py | 15 + c2p/commands/tools/csv2oscal_cd.py | 70 + c2p/commands/tools/tools.py | 28 + c2p/commands/tools/viewer.py | 74 + c2p/commands/version.py | 32 + c2p/common/__init__.py | 15 + c2p/common/c2p_base_model.py | 92 ++ c2p/common/err.py | 37 + c2p/common/logging.py | 47 + c2p/common/oscal.py | 37 + c2p/common/utils.py | 100 ++ c2p/framework/__init__.py | 21 + c2p/framework/c2p.py | 211 +++ c2p/framework/models/__init__.py | 19 + c2p/framework/models/c2p_config.py | 59 + c2p/framework/models/policy.py | 52 + c2p/framework/models/pvp_result.py | 132 ++ c2p/framework/models/raw_result.py | 46 + c2p/framework/oscal_utils.py | 118 ++ c2p/framework/plugin_spec.py | 37 + c2p/tools/__init__.py | 15 + c2p/tools/oscal_csv_to_json.py | 70 + c2p/tools/viewer/__init__.py | 17 + c2p/tools/viewer/template.py | 47 + c2p/tools/viewer/viewer.py | 113 ++ .../images/assessment-results-md.kyverno.jpg | Bin 0 -> 82472 bytes .../images/assessment-results-md.ocm.jpg | Bin 0 -> 100067 bytes docs/public/kyverno.md | 63 + docs/public/ocm.md | 194 +++ .dockerignore => go/.dockerignore | 0 go/.gitignore | 43 + .golangci.yaml => go/.golangci.yaml | 0 .goreleaser.yaml => go/.goreleaser.yaml | 0 Dockerfile => go/Dockerfile | 0 go/Makefile | 324 ++++ PROJECT => go/PROJECT | 6 +- go/README.md | 52 + {api => go/api}/v1alpha1/checkpolicy_types.go | 0 .../v1alpha1/compliancedeployment_types.go | 0 .../api}/v1alpha1/compliancereport_types.go | 2 +- .../v1alpha1/controlreference_common_types.go | 0 .../api}/v1alpha1/controlreference_types.go | 0 .../v1alpha1/controlreferencekcp_types.go | 0 {api => go/api}/v1alpha1/groupversion_info.go | 0 .../api}/v1alpha1/resultcollector_types.go | 0 .../api}/v1alpha1/zz_generated.deepcopy.go | 0 {cmd => go/cmd}/c2pcli/cmd/cmd.go | 4 +- {cmd => go/cmd}/c2pcli/main.go | 2 +- {cmd => go/cmd}/c2pcli/options/options.go | 0 {cmd => go/cmd}/c2pcli/subcommands/kyverno.go | 8 +- {cmd => go/cmd}/c2pcli/subcommands/ocm.go | 8 +- {cmd => go/cmd}/decompose/decompose.go | 4 +- .../cmd}/kyverno/oscal2policy/cmd/cmd.go | 8 +- .../cmd/kyverno/oscal2policy}/main.go | 2 +- .../kyverno/oscal2policy/options/options.go | 0 .../cmd}/kyverno/result2oscal/cmd/cmd.go | 8 +- .../cmd/kyverno/result2oscal}/main.go | 2 +- .../kyverno/result2oscal/options/options.go | 0 {cmd => go/cmd}/kyverno/tools/cmd/cmd.go | 8 +- .../cmd}/kyverno/tools/options/options.go | 0 .../kyverno/tools/subcommands/kyverno/cmd.go | 4 +- .../tools/subcommands/kyverno/options.go | 0 {cmd => go/cmd}/ocm/oscal2policy/cmd/cmd.go | 8 +- .../cmd/ocm/oscal2policy}/main.go | 2 +- .../cmd}/ocm/oscal2policy/options/options.go | 0 {cmd => go/cmd}/ocm/result2oscal/cmd/cmd.go | 8 +- .../cmd/ocm/result2oscal}/main.go | 2 +- .../cmd}/ocm/result2oscal/options/options.go | 0 {cmd => go/cmd}/ocm/tools/cmd/cmd.go | 6 +- {cmd => go/cmd}/ocm/tools/options/options.go | 0 {cmd => go/cmd}/parse-single/parse-single.go | 2 +- {cmd => go/cmd}/parse/modules/parse.go | 8 +- {cmd => go/cmd}/parse/parse.go | 2 +- {cmd => go/cmd}/publisher/publisher.go | 10 +- .../samples/compliancedeployment.yaml | 0 .../samples/component-definition.json | 0 .../samples/component-definition.low.json | 0 .../cmd}/pvpcommon/oscal2posture/cmd/cmd.go | 10 +- .../oscal2posture/options/options.go | 0 {cmd => go/cmd}/viewer/viewer.go | 6 +- {config => go/config}/crd/bases/_.yaml | 0 ...compliance-to-policy.io_checkpolicies.yaml | 0 ...ce-to-policy.io_compliancedeployments.yaml | 0 ...liance-to-policy.io_compliancereports.yaml | 0 ...nce-to-policy.io_controlreferencekcps.yaml | 0 ...liance-to-policy.io_controlreferences.yaml | 0 ...pliance-to-policy.io_resultcollectors.yaml | 0 .../wgpolicyk8s.io_clusterpolicyreports.yaml | 0 .../bases/wgpolicyk8s.io_policyreports.yaml | 0 {config => go/config}/crd/kustomization.yaml | 0 .../config}/crd/kustomizeconfig.yaml | 0 .../cainjection_in_compliancedeployments.yaml | 0 .../cainjection_in_controlreferences.yaml | 0 .../webhook_in_compliancedeployments.yaml | 0 .../patches/webhook_in_controlreferences.yaml | 0 .../config}/default/kustomization.yaml | 0 .../default/manager_auth_proxy_patch.yaml | 0 .../config}/default/manager_config_patch.yaml | 0 .../config}/manager/kustomization.yaml | 0 {config => go/config}/manager/manager.yaml | 0 .../config}/manifests/kustomization.yaml | 0 ...ster-management.io_placementrules_crd.yaml | 0 ...uster-management.io_placementbindings.yaml | 0 ...y.open-cluster-management.io_policies.yaml | 0 ...open-cluster-management.io_policysets.yaml | 0 .../config}/prometheus/kustomization.yaml | 0 {config => go/config}/prometheus/monitor.yaml | 0 .../rbac/auth_proxy_client_clusterrole.yaml | 0 .../config}/rbac/auth_proxy_role.yaml | 0 .../config}/rbac/auth_proxy_role_binding.yaml | 0 .../config}/rbac/auth_proxy_service.yaml | 0 .../compliancedeployment_editor_role.yaml | 0 .../compliancedeployment_viewer_role.yaml | 0 .../rbac/controlreference_editor_role.yaml | 0 .../rbac/controlreference_viewer_role.yaml | 0 {config => go/config}/rbac/kustomization.yaml | 0 .../config}/rbac/leader_election_role.yaml | 0 .../rbac/leader_election_role_binding.yaml | 0 {config => go/config}/rbac/role.yaml | 0 {config => go/config}/rbac/role_binding.yaml | 0 .../config}/rbac/service_account.yaml | 0 ...icy_v1alpha1_compliancedeployment.kcp.yaml | 0 ...-policy_v1alpha1_compliancedeployment.yaml | 0 ...e-to-policy_v1alpha1_controlreference.yaml | 0 ...o-policy_v1alpha1_controlreferencekcp.yaml | 0 .../config}/samples/kustomization.yaml | 0 .../config}/scorecard/bases/config.yaml | 0 .../config}/scorecard/kustomization.yaml | 0 .../scorecard/patches/basic.config.yaml | 0 .../config}/scorecard/patches/olm.config.yaml | 0 .../wgpolicyk8s.io_clusterpolicyreports.yaml | 0 .../wgpolicyk8s.io_policyreports.yaml | 0 .../wgpolicyk8s.io_clusterpolicyreports.yaml | 0 .../wgpolicyk8s.io_policyreports.yaml | 0 .../wgpolicyk8s.io_clusterpolicyreports.yaml | 0 .../v1beta1/wgpolicyk8s.io_policyreports.yaml | 0 .../compliancedeployment/controller.go | 4 +- .../compliancedeployment/controller_test.go | 10 +- .../controllers}/composer/composer.go | 8 +- .../controllers}/composer/composer_test.go | 10 +- .../controllers}/composer/helper.go | 10 +- .../composer/testdata/compliance.yaml | 0 .../add-chrony.yaml | 0 .../install-odf-lvm-operator.yaml | 0 .../policy-nginx-deployment.yaml | 0 .../add-chrony/add-chrony.yaml | 0 .../install-odf-lvm-operator.yaml | 0 .../install-odf-lvm-operator2.yaml | 0 .../install-odf-lvm-operator3.yaml | 0 .../install-odf-lvm-operator4.yaml | 0 .../composed-policies/add-chrony.yaml | 0 .../install-odf-lvm-operator.yaml | 0 .../composer/testdata/oscal/catalog.json | 0 .../testdata/oscal/component-definition.json | 0 .../composer/testdata/oscal/profile.json | 0 .../MachineConfig.50-worker-chrony.0.yaml | 0 .../policies/add-chrony/kustomization.yaml | 0 .../policies/add-chrony/policy-generator.yaml | 0 .../kustomization.yaml | 0 .../LVMCluster.odf-lvmcluster.0.yaml | 0 .../policy-generator.yaml | 0 .../Namespace.openshift-storage.0.yaml | 0 ...oup.openshift-storage-operatorgroup.0.yaml | 0 .../Subscription.lvm-operator.0.yaml | 0 .../kustomization.yaml | 0 .../policy-generator.yaml | 0 .../Deployment.nginx-deployment.0.yaml | 0 .../controlreference/kcp/controller.go | 12 +- .../controlreference/kcp/controller_test.go | 8 +- .../controlreference/kcp/helper.go | 8 +- .../controlreference/ocm/controller.go | 14 +- .../controlreference/ocm/controller_test.go | 8 +- .../edge.kcp.io/v1alpha1/customize.go | 0 .../edge.kcp.io/v1alpha1/edge-placement.go | 0 .../edge.kcp.io/v1alpha1/single-placement.go | 0 .../controllers}/resultcollector/collector.go | 8 +- .../resultcollector/controller.go | 4 +- .../controllers}/resultcollector/validator.go | 6 +- .../testdata/compliancedeployment.yaml | 0 .../configmap.component-definition.yaml | 0 .../testdata/controlreference.yaml | 0 .../testdata/controlreferencekcp.yaml | 0 .../controllers}/testdata/ws.test1.yaml | 0 .../controllers}/testdata/ws.test2.yaml | 0 .../controllers}/testsetting/common.go | 0 .../testsetting/kcptestsetting.go | 4 +- .../controllers}/testsetting/testsetting.go | 6 +- .../controllers}/utils/gitrepo/gitrepo.go | 0 .../utils/gitrepo/gitrepo_test.go | 2 +- .../controllers}/utils/kcpclient/kcpclient.go | 0 .../utils/kcpclient/kcpclient_test.go | 4 +- .../utils/kcpclient/testdata/ws.test1.yaml | 0 .../utils/kcpclient/testdata/ws.test2.yaml | 0 .../utils/ocmk8sclients/ocmk8sclient.go | 0 .../ocmk8sclients/placementbindingclient.go | 4 +- .../placementbindingclient_test.go | 4 +- .../ocmk8sclients/placementruleclient.go | 4 +- .../ocmk8sclients/placementruleclient_test.go | 4 +- .../utils/ocmk8sclients/policyclient.go | 4 +- .../utils/ocmk8sclients/policyclient_test.go | 4 +- .../utils/ocmk8sclients/suite_test.go | 4 +- .../testdata/placement-binding.sample.yaml | 0 .../testdata/placement-rule.sample.yaml | 0 .../ocmk8sclients/testdata/policy.sample.yaml | 0 .../controllers}/utils/publisher/publisher.go | 10 +- .../testdata/compliancedeployment.yaml | 0 .../testdata/component-definition.json | 0 .../controllers}/utils/utils.go | 16 +- .../v1alpha1/clusterpolicyreport_types.go | 0 .../wgpolicyk8s.io/v1alpha1/doc.go | 0 .../v1alpha1/groupversion_info.go | 0 .../v1alpha1/policyreport_types.go | 0 .../v1alpha1/zz_generated.deepcopy.go | 0 .../v1alpha2/clusterpolicyreport_types.go | 0 .../wgpolicyk8s.io/v1alpha2/doc.go | 0 .../v1alpha2/groupversion_info.go | 0 .../v1alpha2/policyreport_types.go | 0 .../v1alpha2/zz_generated.deepcopy.go | 0 .../v1beta1/clusterpolicyreport_types.go | 0 .../wgpolicyk8s.io/v1beta1/doc.go | 0 .../v1beta1/groupversion_info.go | 0 .../v1beta1/policyreport_types.go | 0 .../v1beta1/zz_generated.deepcopy.go | 0 {docs => go/docs}/images/e2e-pm.drawio | 0 {docs => go/docs}/images/e2e-pm.png | Bin {docs => go/docs}/kyverno/README.md | 4 +- .../docs}/kyverno/kyverno-workflow.drawio | 0 .../oscal-vs-kyverno-result-mapping.csv | 0 {docs => go/docs}/ocm/README.md | 6 +- {docs => go/docs}/ocm/c2p-config.yaml | 0 .../ocm/final-outputs/assessment-results.json | 0 .../ocm/final-outputs/compliance-posture.md | 0 .../ConfigMap.c2p.c2p-parameters.yaml | 0 ...ment.c2p.placement-managed-kubernetes.yaml | 0 .../PlacementBinding.c2p.policy-set.yaml | 0 .../Policy.c2p.policy-deployment.yaml | 0 .../Policy.c2p.policy-high-scan.yaml | 0 ...policy-install-kyverno-from-manifests.yaml | 0 ...icy.c2p.policy-kyverno-require-labels.yaml | 0 .../PolicySet.c2p.managed-kubernetes.yaml | 0 .../images/manual-end-to-end-use-case.drawio | 0 .../ocm/images/manual-end-to-end-use-case.png | Bin .../ocm/oscal-ar-vs-ocm-status-mapping.csv | 0 .../docs}/ocm/oscal/component-definition.csv | 0 .../docs}/ocm/oscal/component-definition.json | 0 {docs => go/docs}/ocm/oscal/profile.json | 0 go.mod => go/go.mod | 2 +- go.sum => go/go.sum | 0 {hack => go/hack}/add-header.sh | 0 {hack => go/hack}/boilerplate.go.txt | 0 {hack => go/hack}/boilerplate.sh.txt | 0 .../hack}/cleanup-tmp-files-in-tests.sh | 0 {hack => go/hack}/format/format.py | 0 {hack => go/hack}/format/requirements.txt | 0 {hack => go/hack}/policy-checker/.gitignore | 0 {hack => go/hack}/policy-checker/README.md | 0 {hack => go/hack}/policy-checker/check.py | 0 {hack => go/hack}/policy-checker/common.py | 0 .../policy-checker/list_generated_policies.py | 0 .../hack}/policy-checker/requirements.txt | 0 main.go => go/main.go | 18 +- {pkg => go/pkg}/decomposer/decomposer.go | 8 +- {pkg => go/pkg}/gitutils.go | 0 {pkg => go/pkg}/kyverno/configparser.go | 8 +- {pkg => go/pkg}/kyverno/fileloader.go | 2 +- {pkg => go/pkg}/kyverno/oscal2policy.go | 4 +- {pkg => go/pkg}/kyverno/oscal2policy_test.go | 4 +- {pkg => go/pkg}/kyverno/result2oscal.go | 10 +- {pkg => go/pkg}/ocm/configparser.go | 6 +- {pkg => go/pkg}/ocm/helper.go | 4 +- {pkg => go/pkg}/ocm/oscal2policy.go | 10 +- {pkg => go/pkg}/ocm/oscal2policy_test.go | 4 +- {pkg => go/pkg}/ocm/result2oscal.go | 18 +- {pkg => go/pkg}/ocm/result2oscal_test.go | 6 +- {pkg => go/pkg}/oscal/oscal.go | 12 +- {pkg => go/pkg}/oscal/oscal_test.go | 12 +- {pkg => go/pkg}/oscal/parser.go | 2 +- ..._SP-800-53_rev5_HIGH-baseline_profile.json | 0 ...T_SP-800-53_rev5_LOW-baseline_profile.json | 0 ...800-53_rev5_MODERATE-baseline_profile.json | 0 .../testdata/NIST_SP-800-53_rev5_catalog.json | 0 .../oscal/testdata/component-definition.json | 0 {pkg => go/pkg}/oscal/testdata/resources.csv | 0 .../results/interna-oscal-standards-high.yaml | 0 .../results/interna-oscal-standards-low.yaml | 0 .../interna-oscal-standards-moderate.yaml | 0 .../results/interna-oscal-standards.yaml | 0 .../results/internal-compliance-from-cd.yaml | 0 .../testdata/results/internal-compliance.yaml | 0 {pkg => go/pkg}/parser/parser.go | 14 +- {pkg => go/pkg}/parser/parser_test.go | 2 +- .../parser/testdata/expected/policies.csv | 0 .../parser/testdata/expected/resources.csv | 0 {pkg => go/pkg}/parser/testdata/policy.yaml | 0 {pkg => go/pkg}/parser/util.go | 0 {pkg => go/pkg}/parser/yamlloder.go | 4 +- {pkg => go/pkg}/parser/yamlloder_test.go | 4 +- .../pkg}/policygenerator/policygenerator.go | 2 +- .../policygenerator/policygenerator_test.go | 2 +- .../input-kustomize/base/kustomization.yaml | 0 .../input-kustomize/base/nginx-pod.yaml | 0 .../input-kustomize/dev/kustomization.yml | 0 .../input-kustomize/kustomization.yml | 0 .../input-kustomize/prod/kustomization.yml | 0 .../testdata/kustomization.yml | 0 .../testdata/policyGenerator-kustomize.yaml | 0 {pkg => go/pkg}/pvpcommon/oscal2posture.go | 10 +- {pkg => go/pkg}/pvpcommon/template/model.go | 0 .../pkg}/pvpcommon/template/template.md | 0 .../pkg}/tables/resources/resource-table.go | 2 +- {pkg => go/pkg}/tables/table.go | 0 {pkg => go/pkg}/testdata/compliance.yaml | 0 .../pkg}/testdata/kyverno/c2p-config.yaml | 0 .../kyverno/component-definition.json | 0 .../clusterpolicies.kyverno.io.yaml | 0 .../clusterpolicyreports.wgpolicyk8s.io.yaml | 0 .../policy-reports/policies.kyverno.io.yaml | 0 .../policyreports.wgpolicyk8s.io.yaml | 0 .../allowed-base-images/02-setup-cm.yaml | 0 .../allowed-base-images.yaml | 0 .../pkg}/testdata/ocm/assessment-results.json | 0 {pkg => go/pkg}/testdata/ocm/catalog.json | 0 .../testdata/ocm/component-definition.json | 0 .../MachineConfig.50-worker-chrony.0.yaml | 0 .../policies/add-chrony/kustomization.yaml | 0 .../policies/add-chrony/policy-generator.yaml | 0 .../kustomization.yaml | 0 .../LVMCluster.odf-lvmcluster.0.yaml | 0 .../policy-generator.yaml | 0 .../Namespace.openshift-storage.0.yaml | 0 ...oup.openshift-storage-operatorgroup.0.yaml | 0 .../Subscription.lvm-operator.0.yaml | 0 .../policy-deployment/kustomization.yaml | 0 .../policy-deployment/policy-generator.yaml | 0 .../Deployment.nginx-deployment.0.yaml | 0 .../kustomization.yaml | 0 .../Role.noname.0.yaml | 0 .../policy-generator.yaml | 0 .../ScanSettingBinding.high.0.yaml | 0 .../ComplianceCheckResult.noname.0.yaml | 0 .../ComplianceSuite.high.0.yaml | 0 .../policy-high-scan/kustomization.yaml | 0 .../policy-high-scan/policy-generator.yaml | 0 .../kustomization.yaml | 0 .../policy-generator.yaml | 0 .../ClusterRole.kyverno.yaml | 0 ...terRole.kyverno:admin-generaterequest.yaml | 0 .../ClusterRole.kyverno:admin-policies.yaml | 0 ...lusterRole.kyverno:admin-policyreport.yaml | 0 .../ClusterRole.kyverno:admin-reports.yaml | 0 ...usterRole.kyverno:admin-updaterequest.yaml | 0 .../ClusterRole.kyverno:events.yaml | 0 .../ClusterRole.kyverno:generate.yaml | 0 .../ClusterRole.kyverno:policies.yaml | 0 .../ClusterRole.kyverno:userinfo.yaml | 0 .../ClusterRole.kyverno:view.yaml | 0 .../ClusterRole.kyverno:webhook.yaml | 0 .../ClusterRoleBinding.kyverno.yaml | 0 .../ConfigMap.kyverno-metrics.yaml | 0 .../ConfigMap.kyverno.yaml | 0 ...efinition.admissionreports.kyverno.io.yaml | 0 ...tion.backgroundscanreports.kyverno.io.yaml | 0 ...on.clusteradmissionreports.kyverno.io.yaml | 0 ...usterbackgroundscanreports.kyverno.io.yaml | 0 ...Definition.clusterpolicies.kyverno.io.yaml | 0 ...n.clusterpolicyreports.wgpolicyk8s.io.yaml | 0 ...efinition.generaterequests.kyverno.io.yaml | 0 ...esourceDefinition.policies.kyverno.io.yaml | 0 ...finition.policyreports.wgpolicyk8s.io.yaml | 0 ...eDefinition.updaterequests.kyverno.io.yaml | 0 .../Deployment.kyverno.yaml | 0 .../Namespace.kyverno.yaml | 0 .../Role.kyverno:leaderelection.yaml | 0 .../RoleBinding.kyverno:leaderelection.yaml | 0 .../Service.kyverno-svc-metrics.yaml | 0 .../Service.kyverno-svc.yaml | 0 .../ServiceAccount.kyverno.yaml | 0 .../check-kyverno-reports/require-lables.yaml | 0 .../kustomization.yaml | 0 .../policy-generator.yaml | 0 .../ClusterPolicy.require-labels.0.yaml | 0 .../kustomization.yaml | 0 .../policy-generator.yaml | 0 .../Deployment.nginx-deployment.0.yaml | 0 ...ns.cluster.open-cluster-management.io.yaml | 0 ...ies.policy.open-cluster-management.io.yaml | 0 ...ets.policy.open-cluster-management.io.yaml | 0 {pkg => go/pkg}/testdata/ocm/profile.json | 0 {pkg => go/pkg}/testdata/oscal/catalog.json | 0 {pkg => go/pkg}/testdata/oscal/profile.json | 0 {pkg => go/pkg}/types/c2pcr/c2pcr_type.go | 0 .../pkg}/types/c2pcr/c2pcrparsed_type.go | 6 +- .../configurationpolicy_types.go | 0 .../internalcompliance/compliance_type.go | 0 .../assessmentresult_types.go | 2 +- {pkg => go/pkg}/types/oscal/catalog_types.go | 0 .../pkg}/types/oscal/common/common_types.go | 0 .../component-definition.template.json | 0 .../componentdefinition_types.go | 0 {pkg => go/pkg}/types/oscal/profile_types.go | 0 .../pkg}/types/placementdecision/helper.go | 0 .../placementdecision_types.go | 0 .../placements/placementbinding_types.go | 0 .../types/placements/placementrule_types.go | 0 {pkg => go/pkg}/types/policy/helper.go | 0 {pkg => go/pkg}/types/policy/policy_types.go | 0 .../pkg}/types/policy/policyset_types.go | 0 .../policycomposition_type.go | 0 .../policygenerator/policygenerator_type.go | 0 {pkg => go/pkg}/types/report/report_type.go | 0 {pkg => go/pkg}/types/utils/utils.go | 0 {pkg => go/pkg}/utils.go | 0 {scripts => go/scripts}/README.md | 0 {scripts => go/scripts}/cleanup-argocd.sh | 0 {scripts => go/scripts}/collect/cronjob.yaml | 0 {scripts => go/scripts}/collect/rbac.yaml | 0 {scripts => go/scripts}/docker/Dockerfile | 0 .../scripts}/docker/install-kubectl.sh | 0 .../scripts}/gitops/acm-webhook.yaml | 0 {scripts => go/scripts}/gitops/channel.yaml | 0 .../scripts}/gitops/subscription-admin.yaml | 0 .../scripts}/gitops/subscription.yaml | 0 {scripts => go/scripts}/init.sh | 0 {scripts => go/scripts}/install-argocd.sh | 0 {scripts => go/scripts}/kyverno/README.md | 0 .../scripts}/kyverno/collect/cronjob.yaml | 0 .../scripts}/kyverno/collect/rbac.yaml | 0 {scripts => go/scripts}/pod.yaml | 0 {scripts => go/scripts}/setup-argocd.sh | 0 {scripts => go/scripts}/uninstall-argocd.sh | 0 plugins_public/plugins/__init__.py | 15 + plugins_public/plugins/kyverno.py | 153 ++ plugins_public/plugins/ocm.py | 294 ++++ plugins_public/tests/__init__.py | 15 + .../clusterpolicyreports.wgpolicyk8s.io.yaml | 5 + .../data/kyverno/component-definition.csv | 6 + .../data/kyverno/component-definition.json | 210 +++ .../allowed-base-images/02-setup-cm.yaml | 12 + .../allowed-base-images.yaml | 58 + .../disallow-capabilities.yaml | 53 + .../add-imagepullsecrets.yaml | 30 + .../allowed-base-images/02-setup-cm.yaml | 12 + .../allowed-base-images.yaml | 58 + .../disallow-capabilities.yaml | 53 + .../kyverno/policyreports.wgpolicyk8s.io.yaml | 1311 +++++++++++++++++ .../tests/data/ocm/component-definition.csv | 8 + .../tests/data/ocm/component-definition.json | 275 ++++ .../ocm/deliverable-policy/kustomization.yaml | 10 + .../ocm/deliverable-policy/parameters.yaml | 7 + .../policy-deployment/kustomization.yaml | 2 + .../policy-deployment/policy-generator.yaml | 23 + .../Deployment.nginx-deployment.0.yaml | 21 + .../kustomization.yaml | 2 + .../Role.noname.0.yaml | 9 + .../policy-generator.yaml | 23 + .../deliverable-policy/policy-generator.yaml | 89 ++ .../ScanSettingBinding.high.0.yaml | 16 + .../ComplianceCheckResult.noname.0.yaml | 7 + .../ComplianceSuite.high.0.yaml | 7 + .../policy-high-scan/kustomization.yaml | 2 + .../policy-high-scan/policy-generator.yaml | 31 + ...ns.cluster.open-cluster-management.io.yaml | 29 + ...ies.policy.open-cluster-management.io.yaml | 901 +++++++++++ .../policy-deployment/kustomization.yaml | 2 + .../policy-deployment/policy-generator.yaml | 17 + .../Deployment.nginx-deployment.0.yaml | 21 + .../kustomization.yaml | 2 + .../Role.noname.0.yaml | 9 + .../policy-generator.yaml | 17 + .../ScanSettingBinding.high.0.yaml | 16 + .../ComplianceCheckResult.noname.0.yaml | 7 + .../ComplianceSuite.high.0.yaml | 7 + .../policy-high-scan/kustomization.yaml | 2 + .../policy-high-scan/policy-generator.yaml | 25 + ...ets.policy.open-cluster-management.io.yaml | 30 + plugins_public/tests/plugins/__init__.py | 15 + plugins_public/tests/plugins/test_kyverno.py | 76 + plugins_public/tests/plugins/test_ocm.py | 130 ++ plugins_public/tests/utils.py | 32 + pyproject.toml | 95 ++ samples_public/__init__.py | 0 .../kyverno/compliance_to_policy.py | 56 + .../kyverno/result_to_compliance.py | 58 + samples_public/ocm/compliance_to_policy.py | 61 + samples_public/ocm/result_to_compliance.py | 45 + scripts/shell/license.sh | 16 + scripts/shell/license.txt | 16 + tests/__init__.py | 15 + tests/c2p/__init__.py | 32 + tests/c2p/framework/__init__.py | 15 + tests/c2p/framework/test_c2p.py | 94 ++ tests/c2p/test_cli.py | 47 + .../framework/c2p/assessment-results.json | 97 ++ .../framework/c2p/component-definition.json | 107 ++ tests/data/framework/c2p/pvp-result.json | 79 + 509 files changed, 8361 insertions(+), 589 deletions(-) rename .github/{workflows => disabled-workflows}/create-and-publish-image.yml (100%) rename .github/{workflows => disabled-workflows}/goreleaser-workflow.yml (100%) create mode 100644 .pre-commit-config.yaml create mode 100644 .secrets.baseline create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 MAINTAINERS.md create mode 100644 c2p/__init__.py create mode 100644 c2p/__main__.py create mode 100644 c2p/cli.py create mode 100644 c2p/commands/__init__.py create mode 100644 c2p/commands/tools/__init__.py create mode 100644 c2p/commands/tools/csv2oscal_cd.py create mode 100644 c2p/commands/tools/tools.py create mode 100644 c2p/commands/tools/viewer.py create mode 100644 c2p/commands/version.py create mode 100644 c2p/common/__init__.py create mode 100644 c2p/common/c2p_base_model.py create mode 100644 c2p/common/err.py create mode 100644 c2p/common/logging.py create mode 100644 c2p/common/oscal.py create mode 100644 c2p/common/utils.py create mode 100644 c2p/framework/__init__.py create mode 100644 c2p/framework/c2p.py create mode 100644 c2p/framework/models/__init__.py create mode 100644 c2p/framework/models/c2p_config.py create mode 100644 c2p/framework/models/policy.py create mode 100644 c2p/framework/models/pvp_result.py create mode 100644 c2p/framework/models/raw_result.py create mode 100644 c2p/framework/oscal_utils.py create mode 100644 c2p/framework/plugin_spec.py create mode 100644 c2p/tools/__init__.py create mode 100644 c2p/tools/oscal_csv_to_json.py create mode 100644 c2p/tools/viewer/__init__.py create mode 100644 c2p/tools/viewer/template.py create mode 100644 c2p/tools/viewer/viewer.py create mode 100644 docs/public/images/assessment-results-md.kyverno.jpg create mode 100644 docs/public/images/assessment-results-md.ocm.jpg create mode 100644 docs/public/kyverno.md create mode 100644 docs/public/ocm.md rename .dockerignore => go/.dockerignore (100%) create mode 100644 go/.gitignore rename .golangci.yaml => go/.golangci.yaml (100%) rename .goreleaser.yaml => go/.goreleaser.yaml (100%) rename Dockerfile => go/Dockerfile (100%) create mode 100644 go/Makefile rename PROJECT => go/PROJECT (73%) create mode 100644 go/README.md rename {api => go/api}/v1alpha1/checkpolicy_types.go (100%) rename {api => go/api}/v1alpha1/compliancedeployment_types.go (100%) rename {api => go/api}/v1alpha1/compliancereport_types.go (97%) rename {api => go/api}/v1alpha1/controlreference_common_types.go (100%) rename {api => go/api}/v1alpha1/controlreference_types.go (100%) rename {api => go/api}/v1alpha1/controlreferencekcp_types.go (100%) rename {api => go/api}/v1alpha1/groupversion_info.go (100%) rename {api => go/api}/v1alpha1/resultcollector_types.go (100%) rename {api => go/api}/v1alpha1/zz_generated.deepcopy.go (100%) rename {cmd => go/cmd}/c2pcli/cmd/cmd.go (88%) rename {cmd => go/cmd}/c2pcli/main.go (94%) rename {cmd => go/cmd}/c2pcli/options/options.go (100%) rename {cmd => go/cmd}/c2pcli/subcommands/kyverno.go (73%) rename {cmd => go/cmd}/c2pcli/subcommands/ocm.go (73%) rename {cmd => go/cmd}/decompose/decompose.go (91%) rename {cmd => go/cmd}/kyverno/oscal2policy/cmd/cmd.go (86%) rename {cmd/ocm/result2oscal => go/cmd/kyverno/oscal2policy}/main.go (89%) rename {cmd => go/cmd}/kyverno/oscal2policy/options/options.go (100%) rename {cmd => go/cmd}/kyverno/result2oscal/cmd/cmd.go (86%) rename {cmd/kyverno/oscal2policy => go/cmd/kyverno/result2oscal}/main.go (89%) rename {cmd => go/cmd}/kyverno/result2oscal/options/options.go (100%) rename {cmd => go/cmd}/kyverno/tools/cmd/cmd.go (77%) rename {cmd => go/cmd}/kyverno/tools/options/options.go (100%) rename {cmd => go/cmd}/kyverno/tools/subcommands/kyverno/cmd.go (97%) rename {cmd => go/cmd}/kyverno/tools/subcommands/kyverno/options.go (100%) rename {cmd => go/cmd}/ocm/oscal2policy/cmd/cmd.go (89%) rename {cmd/kyverno/result2oscal => go/cmd/ocm/oscal2policy}/main.go (89%) rename {cmd => go/cmd}/ocm/oscal2policy/options/options.go (100%) rename {cmd => go/cmd}/ocm/result2oscal/cmd/cmd.go (86%) rename {cmd/ocm/oscal2policy => go/cmd/ocm/result2oscal}/main.go (89%) rename {cmd => go/cmd}/ocm/result2oscal/options/options.go (100%) rename {cmd => go/cmd}/ocm/tools/cmd/cmd.go (82%) rename {cmd => go/cmd}/ocm/tools/options/options.go (100%) rename {cmd => go/cmd}/parse-single/parse-single.go (95%) rename {cmd => go/cmd}/parse/modules/parse.go (94%) rename {cmd => go/cmd}/parse/parse.go (94%) rename {cmd => go/cmd}/publisher/publisher.go (83%) rename {cmd => go/cmd}/publisher/samples/compliancedeployment.yaml (100%) rename {cmd => go/cmd}/publisher/samples/component-definition.json (100%) rename {cmd => go/cmd}/publisher/samples/component-definition.low.json (100%) rename {cmd => go/cmd}/pvpcommon/oscal2posture/cmd/cmd.go (84%) rename {cmd => go/cmd}/pvpcommon/oscal2posture/options/options.go (100%) rename {cmd => go/cmd}/viewer/viewer.go (92%) rename {config => go/config}/crd/bases/_.yaml (100%) rename {config => go/config}/crd/bases/compliance-to-policy.io_checkpolicies.yaml (100%) rename {config => go/config}/crd/bases/compliance-to-policy.io_compliancedeployments.yaml (100%) rename {config => go/config}/crd/bases/compliance-to-policy.io_compliancereports.yaml (100%) rename {config => go/config}/crd/bases/compliance-to-policy.io_controlreferencekcps.yaml (100%) rename {config => go/config}/crd/bases/compliance-to-policy.io_controlreferences.yaml (100%) rename {config => go/config}/crd/bases/compliance-to-policy.io_resultcollectors.yaml (100%) rename {config => go/config}/crd/bases/wgpolicyk8s.io_clusterpolicyreports.yaml (100%) rename {config => go/config}/crd/bases/wgpolicyk8s.io_policyreports.yaml (100%) rename {config => go/config}/crd/kustomization.yaml (100%) rename {config => go/config}/crd/kustomizeconfig.yaml (100%) rename {config => go/config}/crd/patches/cainjection_in_compliancedeployments.yaml (100%) rename {config => go/config}/crd/patches/cainjection_in_controlreferences.yaml (100%) rename {config => go/config}/crd/patches/webhook_in_compliancedeployments.yaml (100%) rename {config => go/config}/crd/patches/webhook_in_controlreferences.yaml (100%) rename {config => go/config}/default/kustomization.yaml (100%) rename {config => go/config}/default/manager_auth_proxy_patch.yaml (100%) rename {config => go/config}/default/manager_config_patch.yaml (100%) rename {config => go/config}/manager/kustomization.yaml (100%) rename {config => go/config}/manager/manager.yaml (100%) rename {config => go/config}/manifests/kustomization.yaml (100%) rename {config => go/config}/ocm/apps.open-cluster-management.io_placementrules_crd.yaml (100%) rename {config => go/config}/ocm/policy.open-cluster-management.io_placementbindings.yaml (100%) rename {config => go/config}/ocm/policy.open-cluster-management.io_policies.yaml (100%) rename {config => go/config}/ocm/policy.open-cluster-management.io_policysets.yaml (100%) rename {config => go/config}/prometheus/kustomization.yaml (100%) rename {config => go/config}/prometheus/monitor.yaml (100%) rename {config => go/config}/rbac/auth_proxy_client_clusterrole.yaml (100%) rename {config => go/config}/rbac/auth_proxy_role.yaml (100%) rename {config => go/config}/rbac/auth_proxy_role_binding.yaml (100%) rename {config => go/config}/rbac/auth_proxy_service.yaml (100%) rename {config => go/config}/rbac/compliancedeployment_editor_role.yaml (100%) rename {config => go/config}/rbac/compliancedeployment_viewer_role.yaml (100%) rename {config => go/config}/rbac/controlreference_editor_role.yaml (100%) rename {config => go/config}/rbac/controlreference_viewer_role.yaml (100%) rename {config => go/config}/rbac/kustomization.yaml (100%) rename {config => go/config}/rbac/leader_election_role.yaml (100%) rename {config => go/config}/rbac/leader_election_role_binding.yaml (100%) rename {config => go/config}/rbac/role.yaml (100%) rename {config => go/config}/rbac/role_binding.yaml (100%) rename {config => go/config}/rbac/service_account.yaml (100%) rename {config => go/config}/samples/compliance-to-policy_v1alpha1_compliancedeployment.kcp.yaml (100%) rename {config => go/config}/samples/compliance-to-policy_v1alpha1_compliancedeployment.yaml (100%) rename {config => go/config}/samples/compliance-to-policy_v1alpha1_controlreference.yaml (100%) rename {config => go/config}/samples/compliance-to-policy_v1alpha1_controlreferencekcp.yaml (100%) rename {config => go/config}/samples/kustomization.yaml (100%) rename {config => go/config}/scorecard/bases/config.yaml (100%) rename {config => go/config}/scorecard/kustomization.yaml (100%) rename {config => go/config}/scorecard/patches/basic.config.yaml (100%) rename {config => go/config}/scorecard/patches/olm.config.yaml (100%) rename {config => go/config}/wgpolicyk8s/v1alpha1/wgpolicyk8s.io_clusterpolicyreports.yaml (100%) rename {config => go/config}/wgpolicyk8s/v1alpha1/wgpolicyk8s.io_policyreports.yaml (100%) rename {config => go/config}/wgpolicyk8s/v1alpha2/wgpolicyk8s.io_clusterpolicyreports.yaml (100%) rename {config => go/config}/wgpolicyk8s/v1alpha2/wgpolicyk8s.io_policyreports.yaml (100%) rename {config => go/config}/wgpolicyk8s/v1beta1/wgpolicyk8s.io_clusterpolicyreports.yaml (100%) rename {config => go/config}/wgpolicyk8s/v1beta1/wgpolicyk8s.io_policyreports.yaml (100%) rename {controllers => go/controllers}/compliancedeployment/controller.go (96%) rename {controllers => go/controllers}/compliancedeployment/controller_test.go (93%) rename {controllers => go/controllers}/composer/composer.go (96%) rename {controllers => go/controllers}/composer/composer_test.go (94%) rename {controllers => go/controllers}/composer/helper.go (94%) rename {controllers => go/controllers}/composer/testdata/compliance.yaml (100%) rename {controllers => go/controllers}/composer/testdata/expected/c2pcr-parser-composed-policies/add-chrony.yaml (100%) rename {controllers => go/controllers}/composer/testdata/expected/c2pcr-parser-composed-policies/install-odf-lvm-operator.yaml (100%) rename {controllers => go/controllers}/composer/testdata/expected/c2pcr-parser-composed-policies/policy-nginx-deployment.yaml (100%) rename {controllers => go/controllers}/composer/testdata/expected/composed-config-policies/add-chrony/add-chrony.yaml (100%) rename {controllers => go/controllers}/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator.yaml (100%) rename {controllers => go/controllers}/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator2.yaml (100%) rename {controllers => go/controllers}/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator3.yaml (100%) rename {controllers => go/controllers}/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator4.yaml (100%) rename {controllers => go/controllers}/composer/testdata/expected/composed-policies/add-chrony.yaml (100%) rename {controllers => go/controllers}/composer/testdata/expected/composed-policies/install-odf-lvm-operator.yaml (100%) rename {controllers => go/controllers}/composer/testdata/oscal/catalog.json (100%) rename {controllers => go/controllers}/composer/testdata/oscal/component-definition.json (100%) rename {controllers => go/controllers}/composer/testdata/oscal/profile.json (100%) rename {controllers => go/controllers}/composer/testdata/policies/add-chrony/add-chrony-worker/MachineConfig.50-worker-chrony.0.yaml (100%) rename {controllers => go/controllers}/composer/testdata/policies/add-chrony/kustomization.yaml (100%) rename {controllers => go/controllers}/composer/testdata/policies/add-chrony/policy-generator.yaml (100%) rename {controllers => go/controllers}/composer/testdata/policies/install-odf-lvm-operator/kustomization.yaml (100%) rename {controllers => go/controllers}/composer/testdata/policies/install-odf-lvm-operator/odf-lvmcluster/LVMCluster.odf-lvmcluster.0.yaml (100%) rename {controllers => go/controllers}/composer/testdata/policies/install-odf-lvm-operator/policy-generator.yaml (100%) rename {controllers => go/controllers}/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Namespace.openshift-storage.0.yaml (100%) rename {controllers => go/controllers}/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/OperatorGroup.openshift-storage-operatorgroup.0.yaml (100%) rename {controllers => go/controllers}/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Subscription.lvm-operator.0.yaml (100%) rename {controllers => go/controllers}/composer/testdata/policies/policy-nginx-deployment/kustomization.yaml (100%) rename {controllers => go/controllers}/composer/testdata/policies/policy-nginx-deployment/policy-generator.yaml (100%) rename {controllers => go/controllers}/composer/testdata/policies/policy-nginx-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml (100%) rename {controllers => go/controllers}/controlreference/kcp/controller.go (96%) rename {controllers => go/controllers}/controlreference/kcp/controller_test.go (95%) rename {controllers => go/controllers}/controlreference/kcp/helper.go (97%) rename {controllers => go/controllers}/controlreference/ocm/controller.go (93%) rename {controllers => go/controllers}/controlreference/ocm/controller_test.go (93%) rename {controllers => go/controllers}/edge.kcp.io/v1alpha1/customize.go (100%) rename {controllers => go/controllers}/edge.kcp.io/v1alpha1/edge-placement.go (100%) rename {controllers => go/controllers}/edge.kcp.io/v1alpha1/single-placement.go (100%) rename {controllers => go/controllers}/resultcollector/collector.go (97%) rename {controllers => go/controllers}/resultcollector/controller.go (96%) rename {controllers => go/controllers}/resultcollector/validator.go (97%) rename {controllers => go/controllers}/testdata/compliancedeployment.yaml (100%) rename {controllers => go/controllers}/testdata/configmap.component-definition.yaml (100%) rename {controllers => go/controllers}/testdata/controlreference.yaml (100%) rename {controllers => go/controllers}/testdata/controlreferencekcp.yaml (100%) rename {controllers => go/controllers}/testdata/ws.test1.yaml (100%) rename {controllers => go/controllers}/testdata/ws.test2.yaml (100%) rename {controllers => go/controllers}/testsetting/common.go (100%) rename {controllers => go/controllers}/testsetting/kcptestsetting.go (95%) rename {controllers => go/controllers}/testsetting/testsetting.go (94%) rename {controllers => go/controllers}/utils/gitrepo/gitrepo.go (100%) rename {controllers => go/controllers}/utils/gitrepo/gitrepo_test.go (96%) rename {controllers => go/controllers}/utils/kcpclient/kcpclient.go (100%) rename {controllers => go/controllers}/utils/kcpclient/kcpclient_test.go (96%) rename {controllers => go/controllers}/utils/kcpclient/testdata/ws.test1.yaml (100%) rename {controllers => go/controllers}/utils/kcpclient/testdata/ws.test2.yaml (100%) rename {controllers => go/controllers}/utils/ocmk8sclients/ocmk8sclient.go (100%) rename {controllers => go/controllers}/utils/ocmk8sclients/placementbindingclient.go (94%) rename {controllers => go/controllers}/utils/ocmk8sclients/placementbindingclient_test.go (93%) rename {controllers => go/controllers}/utils/ocmk8sclients/placementruleclient.go (94%) rename {controllers => go/controllers}/utils/ocmk8sclients/placementruleclient_test.go (93%) rename {controllers => go/controllers}/utils/ocmk8sclients/policyclient.go (94%) rename {controllers => go/controllers}/utils/ocmk8sclients/policyclient_test.go (93%) rename {controllers => go/controllers}/utils/ocmk8sclients/suite_test.go (96%) rename {controllers => go/controllers}/utils/ocmk8sclients/testdata/placement-binding.sample.yaml (100%) rename {controllers => go/controllers}/utils/ocmk8sclients/testdata/placement-rule.sample.yaml (100%) rename {controllers => go/controllers}/utils/ocmk8sclients/testdata/policy.sample.yaml (100%) rename {controllers => go/controllers}/utils/publisher/publisher.go (89%) rename {controllers => go/controllers}/utils/publisher/testdata/compliancedeployment.yaml (100%) rename {controllers => go/controllers}/utils/publisher/testdata/component-definition.json (100%) rename {controllers => go/controllers}/utils/utils.go (95%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1alpha1/clusterpolicyreport_types.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1alpha1/doc.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1alpha1/groupversion_info.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1alpha1/policyreport_types.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1alpha1/zz_generated.deepcopy.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1alpha2/clusterpolicyreport_types.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1alpha2/doc.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1alpha2/groupversion_info.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1alpha2/policyreport_types.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1alpha2/zz_generated.deepcopy.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1beta1/clusterpolicyreport_types.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1beta1/doc.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1beta1/groupversion_info.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1beta1/policyreport_types.go (100%) rename {controllers => go/controllers}/wgpolicyk8s.io/v1beta1/zz_generated.deepcopy.go (100%) rename {docs => go/docs}/images/e2e-pm.drawio (100%) rename {docs => go/docs}/images/e2e-pm.png (100%) rename {docs => go/docs}/kyverno/README.md (94%) rename {docs => go/docs}/kyverno/kyverno-workflow.drawio (100%) rename {docs => go/docs}/kyverno/oscal-vs-kyverno-result-mapping.csv (100%) rename {docs => go/docs}/ocm/README.md (98%) rename {docs => go/docs}/ocm/c2p-config.yaml (100%) rename {docs => go/docs}/ocm/final-outputs/assessment-results.json (100%) rename {docs => go/docs}/ocm/final-outputs/compliance-posture.md (100%) rename {docs => go/docs}/ocm/final-outputs/ocm-policies/ConfigMap.c2p.c2p-parameters.yaml (100%) rename {docs => go/docs}/ocm/final-outputs/ocm-policies/Placement.c2p.placement-managed-kubernetes.yaml (100%) rename {docs => go/docs}/ocm/final-outputs/ocm-policies/PlacementBinding.c2p.policy-set.yaml (100%) rename {docs => go/docs}/ocm/final-outputs/ocm-policies/Policy.c2p.policy-deployment.yaml (100%) rename {docs => go/docs}/ocm/final-outputs/ocm-policies/Policy.c2p.policy-high-scan.yaml (100%) rename {docs => go/docs}/ocm/final-outputs/ocm-policies/Policy.c2p.policy-install-kyverno-from-manifests.yaml (100%) rename {docs => go/docs}/ocm/final-outputs/ocm-policies/Policy.c2p.policy-kyverno-require-labels.yaml (100%) rename {docs => go/docs}/ocm/final-outputs/ocm-policies/PolicySet.c2p.managed-kubernetes.yaml (100%) rename {docs => go/docs}/ocm/images/manual-end-to-end-use-case.drawio (100%) rename {docs => go/docs}/ocm/images/manual-end-to-end-use-case.png (100%) rename {docs => go/docs}/ocm/oscal-ar-vs-ocm-status-mapping.csv (100%) rename {docs => go/docs}/ocm/oscal/component-definition.csv (100%) rename {docs => go/docs}/ocm/oscal/component-definition.json (100%) rename {docs => go/docs}/ocm/oscal/profile.json (100%) rename go.mod => go/go.mod (99%) rename go.sum => go/go.sum (100%) rename {hack => go/hack}/add-header.sh (100%) rename {hack => go/hack}/boilerplate.go.txt (100%) rename {hack => go/hack}/boilerplate.sh.txt (100%) rename {hack => go/hack}/cleanup-tmp-files-in-tests.sh (100%) rename {hack => go/hack}/format/format.py (100%) rename {hack => go/hack}/format/requirements.txt (100%) rename {hack => go/hack}/policy-checker/.gitignore (100%) rename {hack => go/hack}/policy-checker/README.md (100%) rename {hack => go/hack}/policy-checker/check.py (100%) rename {hack => go/hack}/policy-checker/common.py (100%) rename {hack => go/hack}/policy-checker/list_generated_policies.py (100%) rename {hack => go/hack}/policy-checker/requirements.txt (100%) rename main.go => go/main.go (88%) rename {pkg => go/pkg}/decomposer/decomposer.go (94%) rename {pkg => go/pkg}/gitutils.go (100%) rename {pkg => go/pkg}/kyverno/configparser.go (91%) rename {pkg => go/pkg}/kyverno/fileloader.go (98%) rename {pkg => go/pkg}/kyverno/oscal2policy.go (92%) rename {pkg => go/pkg}/kyverno/oscal2policy_test.go (94%) rename {pkg => go/pkg}/kyverno/result2oscal.go (95%) rename {pkg => go/pkg}/ocm/configparser.go (92%) rename {pkg => go/pkg}/ocm/helper.go (95%) rename {pkg => go/pkg}/ocm/oscal2policy.go (96%) rename {pkg => go/pkg}/ocm/oscal2policy_test.go (94%) rename {pkg => go/pkg}/ocm/result2oscal.go (92%) rename {pkg => go/pkg}/ocm/result2oscal_test.go (92%) rename {pkg => go/pkg}/oscal/oscal.go (95%) rename {pkg => go/pkg}/oscal/oscal_test.go (94%) rename {pkg => go/pkg}/oscal/parser.go (97%) rename {pkg => go/pkg}/oscal/testdata/NIST_SP-800-53_rev5_HIGH-baseline_profile.json (100%) rename {pkg => go/pkg}/oscal/testdata/NIST_SP-800-53_rev5_LOW-baseline_profile.json (100%) rename {pkg => go/pkg}/oscal/testdata/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (100%) rename {pkg => go/pkg}/oscal/testdata/NIST_SP-800-53_rev5_catalog.json (100%) rename {pkg => go/pkg}/oscal/testdata/component-definition.json (100%) rename {pkg => go/pkg}/oscal/testdata/resources.csv (100%) rename {pkg => go/pkg}/oscal/testdata/results/interna-oscal-standards-high.yaml (100%) rename {pkg => go/pkg}/oscal/testdata/results/interna-oscal-standards-low.yaml (100%) rename {pkg => go/pkg}/oscal/testdata/results/interna-oscal-standards-moderate.yaml (100%) rename {pkg => go/pkg}/oscal/testdata/results/interna-oscal-standards.yaml (100%) rename {pkg => go/pkg}/oscal/testdata/results/internal-compliance-from-cd.yaml (100%) rename {pkg => go/pkg}/oscal/testdata/results/internal-compliance.yaml (100%) rename {pkg => go/pkg}/parser/parser.go (94%) rename {pkg => go/pkg}/parser/parser_test.go (94%) rename {pkg => go/pkg}/parser/testdata/expected/policies.csv (100%) rename {pkg => go/pkg}/parser/testdata/expected/resources.csv (100%) rename {pkg => go/pkg}/parser/testdata/policy.yaml (100%) rename {pkg => go/pkg}/parser/util.go (100%) rename {pkg => go/pkg}/parser/yamlloder.go (94%) rename {pkg => go/pkg}/parser/yamlloder_test.go (92%) rename {pkg => go/pkg}/policygenerator/policygenerator.go (97%) rename {pkg => go/pkg}/policygenerator/policygenerator_test.go (96%) rename {pkg => go/pkg}/policygenerator/testdata/input-kustomize/base/kustomization.yaml (100%) rename {pkg => go/pkg}/policygenerator/testdata/input-kustomize/base/nginx-pod.yaml (100%) rename {pkg => go/pkg}/policygenerator/testdata/input-kustomize/dev/kustomization.yml (100%) rename {pkg => go/pkg}/policygenerator/testdata/input-kustomize/kustomization.yml (100%) rename {pkg => go/pkg}/policygenerator/testdata/input-kustomize/prod/kustomization.yml (100%) rename {pkg => go/pkg}/policygenerator/testdata/kustomization.yml (100%) rename {pkg => go/pkg}/policygenerator/testdata/policyGenerator-kustomize.yaml (100%) rename {pkg => go/pkg}/pvpcommon/oscal2posture.go (91%) rename {pkg => go/pkg}/pvpcommon/template/model.go (100%) rename {pkg => go/pkg}/pvpcommon/template/template.md (100%) rename {pkg => go/pkg}/tables/resources/resource-table.go (98%) rename {pkg => go/pkg}/tables/table.go (100%) rename {pkg => go/pkg}/testdata/compliance.yaml (100%) rename {pkg => go/pkg}/testdata/kyverno/c2p-config.yaml (100%) rename {pkg => go/pkg}/testdata/kyverno/component-definition.json (100%) rename {pkg => go/pkg}/testdata/kyverno/policy-reports/clusterpolicies.kyverno.io.yaml (100%) rename {pkg => go/pkg}/testdata/kyverno/policy-reports/clusterpolicyreports.wgpolicyk8s.io.yaml (100%) rename {pkg => go/pkg}/testdata/kyverno/policy-reports/policies.kyverno.io.yaml (100%) rename {pkg => go/pkg}/testdata/kyverno/policy-reports/policyreports.wgpolicyk8s.io.yaml (100%) rename {pkg => go/pkg}/testdata/kyverno/policy-resources/allowed-base-images/02-setup-cm.yaml (100%) rename {pkg => go/pkg}/testdata/kyverno/policy-resources/allowed-base-images/allowed-base-images.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/assessment-results.json (100%) rename {pkg => go/pkg}/testdata/ocm/catalog.json (100%) rename {pkg => go/pkg}/testdata/ocm/component-definition.json (100%) rename {pkg => go/pkg}/testdata/ocm/policies/add-chrony/add-chrony-worker/MachineConfig.50-worker-chrony.0.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/add-chrony/kustomization.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/add-chrony/policy-generator.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/install-odf-lvm-operator/kustomization.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/install-odf-lvm-operator/odf-lvmcluster/LVMCluster.odf-lvmcluster.0.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/install-odf-lvm-operator/policy-generator.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Namespace.openshift-storage.0.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/OperatorGroup.openshift-storage-operatorgroup.0.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Subscription.lvm-operator.0.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-deployment/kustomization.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-deployment/policy-generator.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-disallowed-roles/kustomization.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-disallowed-roles/policy-disallowed-roles-sample-role/Role.noname.0.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-disallowed-roles/policy-generator.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-high-scan/compliance-high-scan/ScanSettingBinding.high.0.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-high-scan/compliance-suite-high-results/ComplianceCheckResult.noname.0.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-high-scan/compliance-suite-high/ComplianceSuite.high.0.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-high-scan/kustomization.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-high-scan/policy-generator.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/kustomization.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-generator.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-generaterequest.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-policies.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-policyreport.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-reports.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-updaterequest.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:events.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:generate.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:policies.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:userinfo.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:view.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:webhook.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRoleBinding.kyverno.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ConfigMap.kyverno-metrics.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ConfigMap.kyverno.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.admissionreports.kyverno.io.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.backgroundscanreports.kyverno.io.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusteradmissionreports.kyverno.io.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterbackgroundscanreports.kyverno.io.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterpolicies.kyverno.io.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterpolicyreports.wgpolicyk8s.io.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.generaterequests.kyverno.io.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.policies.kyverno.io.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.policyreports.wgpolicyk8s.io.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.updaterequests.kyverno.io.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Deployment.kyverno.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Namespace.kyverno.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Role.kyverno:leaderelection.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/RoleBinding.kyverno:leaderelection.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Service.kyverno-svc-metrics.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Service.kyverno-svc.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ServiceAccount.kyverno.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-kyverno-require-labels/check-kyverno-reports/require-lables.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-kyverno-require-labels/kustomization.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-kyverno-require-labels/policy-generator.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-kyverno-require-labels/policy-kyverno-require-labels/ClusterPolicy.require-labels.0.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-nginx-deployment/kustomization.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-nginx-deployment/policy-generator.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policies/policy-nginx-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policy-results/placementdecisions.cluster.open-cluster-management.io.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policy-results/policies.policy.open-cluster-management.io.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/policy-results/policysets.policy.open-cluster-management.io.yaml (100%) rename {pkg => go/pkg}/testdata/ocm/profile.json (100%) rename {pkg => go/pkg}/testdata/oscal/catalog.json (100%) rename {pkg => go/pkg}/testdata/oscal/profile.json (100%) rename {pkg => go/pkg}/types/c2pcr/c2pcr_type.go (100%) rename {pkg => go/pkg}/types/c2pcr/c2pcrparsed_type.go (79%) rename {pkg => go/pkg}/types/configurationpolicy/configurationpolicy_types.go (100%) rename {pkg => go/pkg}/types/internalcompliance/compliance_type.go (100%) rename {pkg => go/pkg}/types/oscal/assessmentresults/assessmentresult_types.go (98%) rename {pkg => go/pkg}/types/oscal/catalog_types.go (100%) rename {pkg => go/pkg}/types/oscal/common/common_types.go (100%) rename {pkg => go/pkg}/types/oscal/componentdefinition/component-definition.template.json (100%) rename {pkg => go/pkg}/types/oscal/componentdefinition/componentdefinition_types.go (100%) rename {pkg => go/pkg}/types/oscal/profile_types.go (100%) rename {pkg => go/pkg}/types/placementdecision/helper.go (100%) rename {pkg => go/pkg}/types/placementdecision/placementdecision_types.go (100%) rename {pkg => go/pkg}/types/placements/placementbinding_types.go (100%) rename {pkg => go/pkg}/types/placements/placementrule_types.go (100%) rename {pkg => go/pkg}/types/policy/helper.go (100%) rename {pkg => go/pkg}/types/policy/policy_types.go (100%) rename {pkg => go/pkg}/types/policy/policyset_types.go (100%) rename {pkg => go/pkg}/types/policycomposition/policycomposition_type.go (100%) rename {pkg => go/pkg}/types/policygenerator/policygenerator_type.go (100%) rename {pkg => go/pkg}/types/report/report_type.go (100%) rename {pkg => go/pkg}/types/utils/utils.go (100%) rename {pkg => go/pkg}/utils.go (100%) rename {scripts => go/scripts}/README.md (100%) rename {scripts => go/scripts}/cleanup-argocd.sh (100%) rename {scripts => go/scripts}/collect/cronjob.yaml (100%) rename {scripts => go/scripts}/collect/rbac.yaml (100%) rename {scripts => go/scripts}/docker/Dockerfile (100%) rename {scripts => go/scripts}/docker/install-kubectl.sh (100%) rename {scripts => go/scripts}/gitops/acm-webhook.yaml (100%) rename {scripts => go/scripts}/gitops/channel.yaml (100%) rename {scripts => go/scripts}/gitops/subscription-admin.yaml (100%) rename {scripts => go/scripts}/gitops/subscription.yaml (100%) rename {scripts => go/scripts}/init.sh (100%) rename {scripts => go/scripts}/install-argocd.sh (100%) rename {scripts => go/scripts}/kyverno/README.md (100%) rename {scripts => go/scripts}/kyverno/collect/cronjob.yaml (100%) rename {scripts => go/scripts}/kyverno/collect/rbac.yaml (100%) rename {scripts => go/scripts}/pod.yaml (100%) rename {scripts => go/scripts}/setup-argocd.sh (100%) rename {scripts => go/scripts}/uninstall-argocd.sh (100%) create mode 100644 plugins_public/plugins/__init__.py create mode 100644 plugins_public/plugins/kyverno.py create mode 100644 plugins_public/plugins/ocm.py create mode 100644 plugins_public/tests/__init__.py create mode 100644 plugins_public/tests/data/kyverno/clusterpolicyreports.wgpolicyk8s.io.yaml create mode 100644 plugins_public/tests/data/kyverno/component-definition.csv create mode 100644 plugins_public/tests/data/kyverno/component-definition.json create mode 100644 plugins_public/tests/data/kyverno/deliverable-policy/allowed-base-images/02-setup-cm.yaml create mode 100644 plugins_public/tests/data/kyverno/deliverable-policy/allowed-base-images/allowed-base-images.yaml create mode 100644 plugins_public/tests/data/kyverno/deliverable-policy/disallow-capabilities/disallow-capabilities.yaml create mode 100644 plugins_public/tests/data/kyverno/policy-resources/add-imagepullsecrets/add-imagepullsecrets.yaml create mode 100644 plugins_public/tests/data/kyverno/policy-resources/allowed-base-images/02-setup-cm.yaml create mode 100644 plugins_public/tests/data/kyverno/policy-resources/allowed-base-images/allowed-base-images.yaml create mode 100644 plugins_public/tests/data/kyverno/policy-resources/disallow-capabilities/disallow-capabilities.yaml create mode 100644 plugins_public/tests/data/kyverno/policyreports.wgpolicyk8s.io.yaml create mode 100644 plugins_public/tests/data/ocm/component-definition.csv create mode 100644 plugins_public/tests/data/ocm/component-definition.json create mode 100644 plugins_public/tests/data/ocm/deliverable-policy/kustomization.yaml create mode 100644 plugins_public/tests/data/ocm/deliverable-policy/parameters.yaml create mode 100755 plugins_public/tests/data/ocm/deliverable-policy/policy-deployment/kustomization.yaml create mode 100755 plugins_public/tests/data/ocm/deliverable-policy/policy-deployment/policy-generator.yaml create mode 100755 plugins_public/tests/data/ocm/deliverable-policy/policy-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml create mode 100755 plugins_public/tests/data/ocm/deliverable-policy/policy-disallowed-roles/kustomization.yaml create mode 100755 plugins_public/tests/data/ocm/deliverable-policy/policy-disallowed-roles/policy-disallowed-roles-sample-role/Role.noname.0.yaml create mode 100755 plugins_public/tests/data/ocm/deliverable-policy/policy-disallowed-roles/policy-generator.yaml create mode 100644 plugins_public/tests/data/ocm/deliverable-policy/policy-generator.yaml create mode 100755 plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/compliance-high-scan/ScanSettingBinding.high.0.yaml create mode 100755 plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/compliance-suite-high-results/ComplianceCheckResult.noname.0.yaml create mode 100755 plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/compliance-suite-high/ComplianceSuite.high.0.yaml create mode 100755 plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/kustomization.yaml create mode 100755 plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/policy-generator.yaml create mode 100644 plugins_public/tests/data/ocm/placementdecisions.cluster.open-cluster-management.io.yaml create mode 100644 plugins_public/tests/data/ocm/policies.policy.open-cluster-management.io.yaml create mode 100755 plugins_public/tests/data/ocm/policy-resources/policy-deployment/kustomization.yaml create mode 100755 plugins_public/tests/data/ocm/policy-resources/policy-deployment/policy-generator.yaml create mode 100755 plugins_public/tests/data/ocm/policy-resources/policy-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml create mode 100755 plugins_public/tests/data/ocm/policy-resources/policy-disallowed-roles/kustomization.yaml create mode 100755 plugins_public/tests/data/ocm/policy-resources/policy-disallowed-roles/policy-disallowed-roles-sample-role/Role.noname.0.yaml create mode 100755 plugins_public/tests/data/ocm/policy-resources/policy-disallowed-roles/policy-generator.yaml create mode 100755 plugins_public/tests/data/ocm/policy-resources/policy-high-scan/compliance-high-scan/ScanSettingBinding.high.0.yaml create mode 100755 plugins_public/tests/data/ocm/policy-resources/policy-high-scan/compliance-suite-high-results/ComplianceCheckResult.noname.0.yaml create mode 100755 plugins_public/tests/data/ocm/policy-resources/policy-high-scan/compliance-suite-high/ComplianceSuite.high.0.yaml create mode 100755 plugins_public/tests/data/ocm/policy-resources/policy-high-scan/kustomization.yaml create mode 100755 plugins_public/tests/data/ocm/policy-resources/policy-high-scan/policy-generator.yaml create mode 100644 plugins_public/tests/data/ocm/policysets.policy.open-cluster-management.io.yaml create mode 100644 plugins_public/tests/plugins/__init__.py create mode 100644 plugins_public/tests/plugins/test_kyverno.py create mode 100644 plugins_public/tests/plugins/test_ocm.py create mode 100644 plugins_public/tests/utils.py create mode 100644 pyproject.toml create mode 100644 samples_public/__init__.py create mode 100644 samples_public/kyverno/compliance_to_policy.py create mode 100644 samples_public/kyverno/result_to_compliance.py create mode 100644 samples_public/ocm/compliance_to_policy.py create mode 100644 samples_public/ocm/result_to_compliance.py create mode 100755 scripts/shell/license.sh create mode 100644 scripts/shell/license.txt create mode 100644 tests/__init__.py create mode 100644 tests/c2p/__init__.py create mode 100644 tests/c2p/framework/__init__.py create mode 100644 tests/c2p/framework/test_c2p.py create mode 100644 tests/c2p/test_cli.py create mode 100644 tests/data/framework/c2p/assessment-results.json create mode 100644 tests/data/framework/c2p/component-definition.json create mode 100644 tests/data/framework/c2p/pvp-result.json diff --git a/.github/workflows/create-and-publish-image.yml b/.github/disabled-workflows/create-and-publish-image.yml similarity index 100% rename from .github/workflows/create-and-publish-image.yml rename to .github/disabled-workflows/create-and-publish-image.yml diff --git a/.github/workflows/goreleaser-workflow.yml b/.github/disabled-workflows/goreleaser-workflow.yml similarity index 100% rename from .github/workflows/goreleaser-workflow.yml rename to .github/disabled-workflows/goreleaser-workflow.yml diff --git a/.gitignore b/.gitignore index a644dd5..5601e50 100644 --- a/.gitignore +++ b/.gitignore @@ -1,43 +1,164 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll +# C extensions *.so -*.dylib -bin -testbin/* -Dockerfile.cross -# Test binary, build with `go test -c` -*.test +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST -# Output of the go coverage tool, specifically when used with LiteIDE -*.out +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec -# Kubernetes Generated files - skip generated files, except for vendored files +# Installer logs +pip-log.txt +pip-delete-this-directory.txt -!vendor/**/zz_generated.* +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ -# editor and IDE paraphernalia -.idea -*.swp -*.swo -*~ +# Translations +*.mo +*.pot +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal -# IDE -.vscode -.idea +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ -# Output of gorelease -dist +# Celery stuff +celerybeat-schedule +celerybeat.pid -# ignore output by test -/**/_test +# SageMath parsed files +*.sage.py -# -policy-collection -out -work -kubeconfig.* \ No newline at end of file +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# vscode +.vscode +config/**/*.local.* \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..ec30804 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,21 @@ +# This is an example configuration to enable detect-secrets in the pre-commit hook. +# Add this file to the root folder of your repository. +# +# Read pre-commit hook framework https://pre-commit.com/ for more details about the structure of config yaml file and how git pre-commit would invoke each hook. +# +# This line indicates we will use the hook from ibm/detect-secrets to run scan during committing phase. +repos: + - repo: https://github.com/ibm/detect-secrets + # If you desire to use a specific version of detect-secrets, you can replace `master` with other git revisions such as branch, tag or commit sha. + # You are encouraged to use static refs such as tags, instead of branch name + # + # Running "pre-commit autoupdate" automatically updates rev to latest tag + rev: 0.13.1+ibm.61.dss + hooks: + - id: detect-secrets # pragma: whitelist secret + # Add options for detect-secrets-hook binary. You can run `detect-secrets-hook --help` to list out all possible options. + # You may also run `pre-commit run detect-secrets` to preview the scan result. + # when "--baseline" without "--use-all-plugins", pre-commit scan with just plugins in baseline file + # when "--baseline" with "--use-all-plugins", pre-commit scan with all available plugins + # add "--fail-on-unaudited" to fail pre-commit for unaudited potential secrets + args: [--baseline, .secrets.baseline, --use-all-plugins] diff --git a/.secrets.baseline b/.secrets.baseline new file mode 100644 index 0000000..7a572f5 --- /dev/null +++ b/.secrets.baseline @@ -0,0 +1,152 @@ +{ + "exclude": { + "files": "go/go.sum|^.secrets.baseline$", + "lines": null + }, + "generated_at": "2024-04-28T07:58:38Z", + "plugins_used": [ + { + "name": "AWSKeyDetector" + }, + { + "name": "ArtifactoryDetector" + }, + { + "name": "AzureStorageKeyDetector" + }, + { + "base64_limit": 4.5, + "name": "Base64HighEntropyString" + }, + { + "name": "BasicAuthDetector" + }, + { + "name": "BoxDetector" + }, + { + "name": "CloudantDetector" + }, + { + "ghe_instance": "github.ibm.com", + "name": "GheDetector" + }, + { + "name": "GitHubTokenDetector" + }, + { + "hex_limit": 3, + "name": "HexHighEntropyString" + }, + { + "name": "IbmCloudIamDetector" + }, + { + "name": "IbmCosHmacDetector" + }, + { + "name": "JwtTokenDetector" + }, + { + "keyword_exclude": null, + "name": "KeywordDetector" + }, + { + "name": "MailchimpDetector" + }, + { + "name": "NpmDetector" + }, + { + "name": "PrivateKeyDetector" + }, + { + "name": "SlackDetector" + }, + { + "name": "SoftlayerDetector" + }, + { + "name": "SquareOAuthDetector" + }, + { + "name": "StripeDetector" + }, + { + "name": "TwilioKeyDetector" + } + ], + "results": { + "README.md": [ + { + "hashed_secret": "845d87d073c35614bfe1fe7f7f3821ea0f175126", + "is_secret": false, + "is_verified": false, + "line_number": 279, + "type": "Base64 High Entropy String", + "verified_result": null + } + ], + "go/controllers/utils/gitrepo/gitrepo.go": [ + { + "hashed_secret": "3aa3f05a1cbf42942040995f7e6842769216bdbc", + "is_secret": false, + "is_verified": false, + "line_number": 104, + "type": "Secret Keyword", + "verified_result": null + } + ], + "go/controllers/utils/utils.go": [ + { + "hashed_secret": "49531b78f7258280352a3f4d6679d963f7cc430c", + "is_secret": false, + "is_verified": false, + "line_number": 308, + "type": "Secret Keyword", + "verified_result": null + }, + { + "hashed_secret": "746637d90e70b787088b90792a905d7e450dd379", + "is_secret": false, + "is_verified": false, + "line_number": 308, + "type": "Secret Keyword", + "verified_result": null + } + ], + "go/docs/ocm/README.md": [ + { + "hashed_secret": "21c50805b553b7a40e48394a5d77d442587ddee2", + "is_secret": false, + "is_verified": false, + "line_number": 141, + "type": "Secret Keyword", + "verified_result": null + } + ], + "go/pkg/gitutils.go": [ + { + "hashed_secret": "49531b78f7258280352a3f4d6679d963f7cc430c", + "is_secret": false, + "is_verified": false, + "line_number": 154, + "type": "Secret Keyword", + "verified_result": null + }, + { + "hashed_secret": "746637d90e70b787088b90792a905d7e450dd379", + "is_secret": false, + "is_verified": false, + "line_number": 154, + "type": "Secret Keyword", + "verified_result": null + } + ] + }, + "version": "0.13.1+ibm.61.dss", + "word_list": { + "file": null, + "hash": null + } +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..6f0e294 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# Contributor Covenant Code of Conduct + +Following to [Code of Conduct of OSCAL COMPASS project](https://github.com/oscal-compass/compliance-trestle/blob/develop/CODE_OF_CONDUCT.md). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..1838ce0 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,186 @@ +## Contributing In General + +Our project welcomes external contributions. If you have an itch, please feel +free to scratch it. + +To contribute code or documentation, please submit a [pull request](https://github.com/oscal-compass/compliance-to-policy/pulls). + +A good way to familiarize yourself with the codebase and contribution process is +to look for and tackle low-hanging fruit in the [issue tracker](https://github.com/oscal-compass/compliance-to-policy/issues). +Before embarking on a more ambitious contribution, please quickly [get in touch](/MAINTAINERS.md) with us. + +**Note: We appreciate your effort, and want to avoid a situation where a contribution +requires extensive rework (by you or by us), sits in backlog for a long time, or +cannot be accepted at all!** + +We have also adopted [Contributor Covenant Code of Conduct](/CODE_OF_CONDUCT.md). + +### Proposing new features + +If you would like to implement a new feature, please [raise an issue](https://github.com/oscal-compass/compliance-to-policy/issues) +labelled `enhancement` before sending a pull request so the feature can be discussed. This is to avoid +you wasting your valuable time working on a feature that the project developers +are not interested in accepting into the code base. + +### Fixing bugs + +If you would like to fix a bug, please [raise an issue](https://github.com/oscal-compass/compliance-to-policy/issues) labelled `bug` before sending a +pull request so it can be tracked. + +### Merge approval + +The project maintainers use LGTM (Looks Good To Me) in comments on the code +review to indicate acceptance. A change requires LGTMs from one of the maintainers. + +For a list of the maintainers, see the [maintainers](/MAINTAINERS.md) page. + +### C2P merging and release workflow + +`C2P` is operating on a simple, yet opinionated, method for continuous integration. It's designed to give developers a coherent understanding of the objectives of other past developers. +The criteria for this are below. Trestle effectively uses a gitflow workflow with one modification: PR's merge into develop are squash merged as one commit. + +In trestle's CI environment this results in the following rules: + +1. All Commit's *MUST* be signed off with `git commit --signoff` irrespective of the author's affiliation. This ensures all code can be attributed. + 1. This is enforced by DCO bot and can be overrided by maintainers presuming at least one commit is signed-off. +1. All commits *SHOULD* use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0-beta.2/) + 1. This is as github, when only one commit is in a PR, will use the native git commit message as the merge commit title. + 1. When only a single commit is provided the commit MUST be an conventional commit and will be checked the `Lint PR` aciton. +1. All PR's title's MUST be formed as an [convention commit](https://www.conventionalcommits.org/en/v1.0.0-beta.2/) + 1. This is checked by the `Lint PR` action +1. All PR's to `main` should close at least one issue by [linking the PR to an issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword). +1. C2P will release on demand. +1. Each feature/fix/chore (PR into develop) be represented by a single commit into develop / main with a coherent title (in the PR). + 1. The C2P preference for doing this is to use squash merge functionality when merging a PR into develop. +1. Developers *MUST* pass the required CI checks for each PR. +1. Developers are encouraged to use GitHub's automated merge process where possible to keep the number of active PR's low. + +## Typing, docstrings and documentation + +`C2P` has a goal of using [PEP 484](https://www.python.org/dev/peps/pep-0484/) type annotations where possible / practical. +The devops process does not _strictly_ enforce typing, however, the expectation is that type coverage is added for new +commits with a focus on quality over quantity (e.g. don't add `Any` everywhere just to meet coverage requirements). +Python typing of functions is an active work in progress. + +## Legal + +Each source file must include a license header for the Apache +Software License 2.0. Using the SPDX format is the simplest approach. +e.g. + +```text +# Copyright (c) 2020 IBM Corp. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +``` + +We have tried to make it as easy as possible to make contributions. This +applies to how we handle the legal aspects of contribution. We use the +same approach - the [Developer's Certificate of Origin 1.1 (DCO)](https://oscal-compass.github.io/compliance-trestle/contributing/DCO/) - that the Linux® Kernel [community](https://elinux.org/Developer_Certificate_Of_Origin) +uses to manage code contributions. + +We simply ask that when submitting a patch for review, the developer +must include a sign-off statement in the commit message. + +Here is an example Signed-off-by line, which indicates that the +submitter accepts the DCO: + +```text +Signed-off-by: John Doe +``` + +You can include this automatically when you commit a change to your +local git repository using the following command: + +```bash +git commit --signoff +``` + +Note that DCO signoff is enforced by [DCO bot](https://github.com/probot/dco). Missing DCO's will be required to be rebased +with a signed off commit before being accepted. + +## Setup - Developing `C2P` + +### Does `C2P` run correctly on my platform + +- Setup a venv for python in .venv directory in the repository root directory. +- Run `make install-dev` + - This will install all python dependencies. + - It will also checkout the submodules required for testing. +- Run `make test` + - This *should* run on all platforms. + +### Setting up `vscode` for python. + +- Use the following commands to setup python: + +```bash +python3 -m venv venv +. ./venv/bin/activate +make install-dev +``` + +- Install vscode plugin [Python extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-python.python) + +- Install vscode plugin [Formatter extension for Visual Studio Code using the Black formatter](https://marketplace.visualstudio.com/items?itemName=ms-python.black-formatter) + +- Configure vscode setting with the black-formatter enabled. The example setting.json is as follows: + ``` + { + "[python]": { + "diffEditor.ignoreTrimWhitespace": false, + "gitlens.codeLens.symbolScopes": [ + "!Module" + ], + "editor.formatOnType": true, + "editor.formatOnSave": true, + "editor.wordBasedSuggestions": "off", + "editor.defaultFormatter": "ms-python.black-formatter", + "editor.tabSize": 4, + }, + "isort.args":["--profile", "black"], + "black-formatter.args": [ + "--line-length=120", + "--skip-string-normalization" + ] + } + ``` +### Testing python + +Tests should be in the test subdirectory. Each file should be named test\_\*.py and each test function should be named test\_\*(). +Tests can be executed by `make test`. + +If you want to debug test, here is the example launch.json. +``` +{ + "version": "0.2.0", + "configurations": [{ + "name": "Pytest current file", + "type": "debugpy", + "request": "launch", + "module": "pytest", + "console": "integratedTerminal", + "args": ["${file}"], + "justMyCode": false + }] +} +``` + +### Code style and formating + +`C2P` uses [Black](https://black.readthedocs.io/en/stable/) for code formatting and [isort](https://pycqa.github.io/isort/) for sorting imports. `make format` runs both tools. + +`C2P` also uses [pre-commit](https://pre-commit.com/) hooks that are integrated into the development process with [detect-secrets](https://github.com/IBM/detect-secrets) to prevent from contaminating any confidential data. + +## For Go project +Please refer to [go/README.md](/go) \ No newline at end of file diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 0000000..97e0413 --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,5 @@ +Compliance-to-Policy (C2P) was designed and open sourced by a team based at [IBM Research](https://www.research.ibm.com/) and others around the world. The list includes: + +Takumi Yanagawa [yana1205](https://github.com/yana1205) + +Yuji Watanabe [yuji-watanabe-jp](https://github.com/yuji-watanabe-jp) \ No newline at end of file diff --git a/Makefile b/Makefile index e7a4ebb..564f761 100644 --- a/Makefile +++ b/Makefile @@ -1,295 +1,49 @@ -# VERSION defines the project version for the bundle. -# Update this value when you upgrade the version of your project. -# To re-generate a bundle for another specific version without changing the standard setup, you can: -# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) -# - use environment variables to overwrite this value (e.g export VERSION=0.0.2) -VERSION ?= 0.0.1 +PYTHON := $(shell pwd)/.venv/bin/python -# CHANNELS define the bundle channels used in the bundle. -# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable") -# To re-generate a bundle for other specific channels without changing the standard setup, you can: -# - use the CHANNELS as arg of the bundle target (e.g make bundle CHANNELS=candidate,fast,stable) -# - use environment variables to overwrite this value (e.g export CHANNELS="candidate,fast,stable") -ifneq ($(origin CHANNELS), undefined) -BUNDLE_CHANNELS := --channels=$(CHANNELS) -endif +.venv: + @echo Please create venv firstly -# DEFAULT_CHANNEL defines the default channel used in the bundle. -# Add a new line here if you would like to change its default config. (E.g DEFAULT_CHANNEL = "stable") -# To re-generate a bundle for any other default channel without changing the default setup, you can: -# - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable) -# - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable") -ifneq ($(origin DEFAULT_CHANNEL), undefined) -BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) -endif -BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) +build: .venv + @$(PYTHON) -m build -# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images. -# This variable is used to construct full image tags for bundle and catalog images. -# -# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both -# github.com/compliance-to-policy-bundle:$VERSION and github.com/compliance-to-policy-catalog:$VERSION. -IMAGE_TAG_BASE ?= github.com/compliance-to-policy +install: .venv + @$(PYTHON) -m pip install . -# BUNDLE_IMG defines the image:tag used for the bundle. -# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=/:) -BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION) +install-dev: .venv + @$(PYTHON) -m pip install ".[dev]" -# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command -BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) +uninstall: .venv + @$(PYTHON) -m pip uninstall compliance-to-policy -# USE_IMAGE_DIGESTS defines if images are resolved via tags or digests -# You can enable this value if you would like to use SHA Based Digests -# To enable set flag to true -USE_IMAGE_DIGESTS ?= false -ifeq ($(USE_IMAGE_DIGESTS), true) - BUNDLE_GEN_FLAGS += --use-image-digests -endif -# Image URL to use all building/pushing image targets -IMG ?= controller:latest -# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. -ENVTEST_K8S_VERSION = 1.25.0 +format: .venv + @$(PYTHON) -m isort . + @$(PYTHON) -m black . -# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) -ifeq (,$(shell go env GOBIN)) -GOBIN=$(shell go env GOPATH)/bin -else -GOBIN=$(shell go env GOBIN) -endif +lint: .venv + @$(PYTHON) -m pylint ./c2p ./tests -# Setting SHELL to bash allows bash commands to be executed by recipes. -# Options are set to exit when a recipe line exits non-zero or a piped command fails. -SHELL = /usr/bin/env bash -o pipefail -.SHELLFLAGS = -ec +.PHONY: docs +docs: .venv + @$(PYTHON) -m mkdocs build -.PHONY: all -all: build +.PHONY: gh-pages + gh-pages: .venv + @$(PYTHON) -m mkdocs gh-deploy -##@ General +# make test ARGS="-n 2 --dist loadscope --log-cli-level DEBUG" TARGET="tests/c2p/test_cli.py" +# TODO: -n 2 (pytest-xdist plugin) results in no logs displayed. +test: ARGS ?= +test: TARGET ?= tests/ +test: .venv test-plugin + @OUTPUT_PATH=/dev/null $(PYTHON) -m pytest $(ARGS) $(TARGET) -# The help target prints out all targets with their descriptions organized -# beneath their categories. The categories are represented by '##@' and the -# target descriptions by '##'. The awk commands is responsible for reading the -# entire set of makefiles included in this invocation, looking for lines of the -# file as xyz: ## something, and then pretty-format the target and help. Then, -# if there's a line with ##@ something, that gets pretty-printed as a category. -# More info on the usage of ANSI control characters for terminal formatting: -# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters -# More info on the awk command: -# http://linuxcommand.org/lc3_adv_awk.php +test-plugin: ARGS ?= +test-plugin: TARGET ?= plugins_public/tests/ +test-plugin: .venv + @OUTPUT_PATH=/dev/null $(PYTHON) -m pytest $(ARGS) $(TARGET) -.PHONY: help -help: ## Display this help. - @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) - -##@ Development - -.PHONY: manifests -manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. - $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases - -.PHONY: generate -generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. - $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." - -.PHONY: fmt -fmt: ## Run go fmt against code. - go fmt ./... - -.PHONY: vet -vet: ## Run go vet against code. - go vet ./... - -.PHONY: test-controllers -test-controllers: manifests generate fmt vet envtest ## Run tests. - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./controllers/... -coverprofile cover.controllers.out -p=1 - -.PHONY: test-pkg -test-pkg: - go test ./pkg/... -coverprofile cover.out - -.PHONY: test -test: test-pkg test-controllers - -##@ Build - -.PHONY: build -build: generate fmt vet ## Build manager binary. - go build -o bin/manager main.go - -.PHONY: run -run: manifests generate fmt vet ## Run a controller from your host. - go run ./main.go - -# If you wish built the manager image targeting other platforms you can use the --platform flag. -# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. -# More info: https://docs.docker.com/develop/develop-images/build_enhancements/ -.PHONY: docker-build -docker-build: test ## Build docker image with the manager. - docker build -t ${IMG} . - -.PHONY: docker-push -docker-push: ## Push docker image with the manager. - docker push ${IMG} - -# PLATFORMS defines the target platforms for the manager image be build to provide support to multiple -# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: -# - able to use docker buildx . More info: https://docs.docker.com/build/buildx/ -# - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/ -# - be able to push the image for your registry (i.e. if you do not inform a valid value via IMG=> than the export will fail) -# To properly provided solutions that supports more than one platform you should use this option. -PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le -.PHONY: docker-buildx -docker-buildx: test ## Build and push docker image for the manager for cross-platform support - # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile - sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross - - docker buildx create --name project-v3-builder - docker buildx use project-v3-builder - - docker buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross - - docker buildx rm project-v3-builder - rm Dockerfile.cross - -##@ Deployment - -ifndef ignore-not-found - ignore-not-found = false -endif - -.PHONY: install -install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. - $(KUSTOMIZE) build config/crd | kubectl apply -f - - -.PHONY: uninstall -uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. - $(KUSTOMIZE) build config/crd | kubectl delete --ignore-not-found=$(ignore-not-found) -f - - -## For development in a non OCM Hub -.PHONY: install-ocm-related-crds -install-ocm-related-crds: - kubectl apply -f config/ocm - -.PHONY: uninstall-ocm-related-crds -uninstall-ocm-related-crds: - kubectl delete --ignore-not-found=$(ignore-not-found) -f config/ocm - -.PHONY: deploy -deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. - cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} - $(KUSTOMIZE) build config/default | kubectl apply -f - - -.PHONY: undeploy -undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. - $(KUSTOMIZE) build config/default | kubectl delete --ignore-not-found=$(ignore-not-found) -f - - -.PHONY: get-policy-resources -get-policy-resources: - kubectl get policy,placementrule,placementbinding - -.PHONY: delete-policy-resources -delete-all-policy-resources: - kubectl delete policy,placementrule,placementbinding --all - -##@ Build Dependencies - -## Location to install dependencies to -LOCALBIN ?= $(shell pwd)/bin -$(LOCALBIN): - mkdir -p $(LOCALBIN) - -## Tool Binaries -KUSTOMIZE ?= $(LOCALBIN)/kustomize -CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen -ENVTEST ?= $(LOCALBIN)/setup-envtest - -## Tool Versions -KUSTOMIZE_VERSION ?= v4.5.7 -CONTROLLER_TOOLS_VERSION ?= v0.10.0 - -KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" -.PHONY: kustomize -kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. -$(KUSTOMIZE): $(LOCALBIN) - test -s $(LOCALBIN)/kustomize || { curl -Ss $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); } - -.PHONY: controller-gen -controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. -$(CONTROLLER_GEN): $(LOCALBIN) - test -s $(LOCALBIN)/controller-gen || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) - -.PHONY: envtest -envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. -$(ENVTEST): $(LOCALBIN) - test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest - -.PHONY: bundle -bundle: manifests kustomize ## Generate bundle manifests and metadata, then validate generated files. - operator-sdk generate kustomize manifests -q - cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) - $(KUSTOMIZE) build config/manifests | operator-sdk generate bundle $(BUNDLE_GEN_FLAGS) - operator-sdk bundle validate ./bundle - -.PHONY: bundle-build -bundle-build: ## Build the bundle image. - docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) . - -.PHONY: bundle-push -bundle-push: ## Push the bundle image. - $(MAKE) docker-push IMG=$(BUNDLE_IMG) - -.PHONY: opm -OPM = ./bin/opm -opm: ## Download opm locally if necessary. -ifeq (,$(wildcard $(OPM))) -ifeq (,$(shell which opm 2>/dev/null)) - @{ \ - set -e ;\ - mkdir -p $(dir $(OPM)) ;\ - OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ - curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.23.0/$${OS}-$${ARCH}-opm ;\ - chmod +x $(OPM) ;\ - } -else -OPM = $(shell which opm) -endif -endif - -# A comma-separated list of bundle images (e.g. make catalog-build BUNDLE_IMGS=example.com/operator-bundle:v0.1.0,example.com/operator-bundle:v0.2.0). -# These images MUST exist in a registry and be pull-able. -BUNDLE_IMGS ?= $(BUNDLE_IMG) - -# The image tag given to the resulting catalog image (e.g. make catalog-build CATALOG_IMG=example.com/operator-catalog:v0.2.0). -CATALOG_IMG ?= $(IMAGE_TAG_BASE)-catalog:v$(VERSION) - -# Set CATALOG_BASE_IMG to an existing catalog image tag to add $BUNDLE_IMGS to that image. -ifneq ($(origin CATALOG_BASE_IMG), undefined) -FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG) -endif - -# Build a catalog image by adding bundle images to an empty catalog using the operator package manager tool, 'opm'. -# This recipe invokes 'opm' in 'semver' bundle add mode. For more information on add modes, see: -# https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator -.PHONY: catalog-build -catalog-build: opm ## Build a catalog image. - $(OPM) index add --container-tool docker --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT) - -# Push the catalog image. -.PHONY: catalog-push -catalog-push: ## Push a catalog image. - $(MAKE) docker-push IMG=$(CATALOG_IMG) - -### -.PHONY: compose-v2 -compose-v2: bin/compose-v2.linux_amd64 bin/compose-v2.darwin_amd64 bin/compose-v2.darwin_arm64 - -bin/compose-v2.linux_amd64: - GOOS=linux GOARCH=amd64 go build -o bin/compose-v2.linux_amd64 ./cmd/compose-v2 - -bin/compose-v2.darwin_amd64: - GOOS=darwin GOARCH=amd64 go build -o bin/compose-v2.darwin_amd64 ./cmd/compose-v2 - -bin/compose-v2.darwin_arm64: - GOOS=darwin GOARCH=arm64 go build -o bin/compose-v2.darwin_arm64 ./cmd/compose-v2 - -bin/compose-v2.%.gz: bin/compose-v2.% - gzip ./bin/compose-v2.$* +clean: .venv + @rm -rf build *.egg-info dist + @find ./plugins -type d \( -name '*.egg-info' -o -name 'dist' \) | while read x; do echo $$x; rm -r $$x ; done + @$(PYTHON) -m pyclean -v . \ No newline at end of file diff --git a/README.md b/README.md index f830bc0..f54dc97 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,294 @@ -# compliance-to-policy -Compliance-to-Policy (C2P) provides the framework to bridge Compliance administration and Policy administration by [OSCAL](https://pages.nist.gov/OSCAL/). OSCAL (Open Security Controls Assessment Language) is a standardized framework developed by NIST for expressing and automating the assessment and management of security controls in machine-readable format (xml, json, yaml) +## Introduction +C2P bridges Compliance and PVPs. C2P takes Compliance requirements and generates technical policies for PVP, and takes PVP native results and generates Compliance Assessment Results. -![C2P Overview](/docs/images/e2e-pm.png) +C2P supports Compliance and PVP as follows: +- Compliance framework + - Open Security Controls Assessment Language (OSCAL) +- PVP + - Kyverno + - Open Cluster Management Governance Policy Framework -## Usage of C2P CLI +C2P reduces the cost to implement the interchange between Compliance artifacts and PVP proprietary artifacts. C2P is extensible to various PVPs through plugin. + +## C2P in Go language (deprecated) +C2P was originally maintained in Go language but now it's maintained in Python. The Go verion is moved to [/go](/go/README.md). + +## Install + +#### From git repo ``` -$ c2pcli -h -C2P CLI +pip install git+https://github.com/oscal-compass/compliance-to-policy.git +``` +You may be asked passphrase of SSH key to access to the git repo. -Usage: - c2pcli [flags] - c2pcli [command] +#### From source +1. Clone the repository + ``` + git clone https://github.com/oscal-compass/compliance-to-policy.git + ``` +1. Go to `compliance-to-policy` + ``` + cd compliance-to-policy + ``` +1. Install + ``` + make install + ``` -Available Commands: - completion Generate the autocompletion script for the specified shell - help Help about any command - kyverno C2P CLI Kyverno plugin - ocm C2P CLI OCM plugin - version Display version +## Quick demo -Flags: - -h, --help help for c2pcli +1. Generate Kyverno Policy (C2P Compliance to Policy) + ``` + python samples_public/kyverno/compliance_to_policy.py -o /tmp/deliverable-policy + ``` + E.g. + ``` + $ python samples_public/kyverno/compliance_to_policy.py -o /tmp/deliverable-policy -Use "c2pcli [command] --help" for more information about a command. -``` + tree /tmp/deliverable-policy + disallow-capabilities + - disallow-capabilities.yaml + allowed-base-images + - 02-setup-cm.yaml + - allowed-base-images.yaml + ``` +1. Deploy the generated policies + ``` + kubectl apply -R -f /tmp/deliverable-policy + ``` + E.g. + ``` + $ kubectl apply -R -f /tmp/deliverable-policy + namespace/platform created + configmap/baseimages created + Warning: Validation failure actions enforce/audit are deprecated, use Enforce/Audit instead. + clusterpolicy.kyverno.io/allowed-base-images created + clusterpolicy.kyverno.io/disallow-capabilities created + ``` +1. Check policy results + ``` + $ kubectl get policyreport,clusterpolicyreport -A + NAMESPACE NAME PASS FAIL WARN ERROR SKIP AGE + kube-system policyreport.wgpolicyk8s.io/cpol-allowed-base-images 0 12 0 0 0 19s + kube-system policyreport.wgpolicyk8s.io/cpol-disallow-capabilities 9 2 0 0 0 19s + kyverno policyreport.wgpolicyk8s.io/cpol-allowed-base-images 0 18 0 0 0 9s + kyverno policyreport.wgpolicyk8s.io/cpol-disallow-capabilities 18 0 0 0 0 9s + local-path-storage policyreport.wgpolicyk8s.io/cpol-allowed-base-images 0 3 0 0 0 16s + local-path-storage policyreport.wgpolicyk8s.io/cpol-disallow-capabilities 3 0 0 0 0 16s + ``` +1. Collect policy/cluster policy reports as PVP Raw results + ``` + kubectl get policyreport -A -o yaml > /tmp/policyreports.wgpolicyk8s.io.yaml + kubectl get clusterpolicyreport -o yaml > /tmp/clusterpolicyreports.wgpolicyk8s.io.yaml + ``` +1. Generate Assessment Result (C2P Result to Compliance) + ``` + python samples_public/kyverno/result_to_compliance.py \ + -polr /tmp/policyreports.wgpolicyk8s.io.yaml \ + -cpolr /tmp/clusterpolicyreports.wgpolicyk8s.io.yaml \ + > /tmp/assessment_results.json + ``` +1. OSCAL Assessment Results is not human readable format. You can see the merged report in markdown by a quick viewer. + ``` + c2p tools viewer -ar /tmp/assessment_results.json -cdef ./plugins_public/tests/data/kyverno/component-definition.json -o /tmp/assessment_results.md + ``` + ![assessment-results-md.kyverno.jpg](/docs/public/images/assessment-results-md.kyverno.jpg) + +## Usage of C2P as a library + +#### Generate PVP Policies from Compliance +1. Create `C2PConfig` object to supply compliance requirements and some metadata (See also [kyverno/compliance_to_policy.py](/samples_public/kyverno/compliance_to_policy.py) for a real example) + ```python + c2p_config = C2PConfig() + c2p_config.compliance = ComplianceOscal() + c2p_config.compliance.component_definition = 'plugins_public/tests/data/kyverno/component-definition.json' + c2p_config.pvp_name = 'Kyverno' + c2p_config.result_title = 'Kyverno Assessment Results' + c2p_config.result_description = 'OSCAL Assessment Results from Kyverno' + ``` +1. Select a plugin for supported PVPs (`PluginKyverno`, `PluginOCM`) and create `PluginConfig` object to supply plugin specific properties + ```python + from plugins_public.plugins.kyverno import PluginConfigKyverno, PluginKyverno + policy_template_dir = 'plugins_public/tests/data/kyverno/policy-resources' + config = PluginConfigKyverno(policy_template_dir=policy_template_dir, deliverable_policy_dir='/tmp/deliverable-policies') + ``` +1. Create `C2P` and `Plugin` + ```python + c2p = C2P(c2p_config) + plugin = PluginKyverno(config) + ``` +1. Get policy from `c2p` and generate PVP policy by `generate_pvp_policy()` + ```python + policy = c2p.get_policy() + plugin.generate_pvp_policy(policy) + ``` +1. The deliverable policies are output in '/tmp/deliverable-policies' + ``` + $ tree /tmp/deliverable-policy + /tmp/deliverable-policy + ├── allowed-base-images + │ ├── 02-setup-cm.yaml + │ └── allowed-base-images.yaml + └── disallow-capabilities + └── disallow-capabilities.yaml + ``` +#### Generate Compliance Assessment Results from PVP native results +1. Create `C2PConfig` object to supply compliance requirements and some metadata (See also [kyverno/compliance_to_policy.py](/samples_public/kyverno/result_to_compliance.py) for a real example) + ```python + c2p_config = C2PConfig() + c2p_config.compliance = ComplianceOscal() + c2p_config.compliance.component_definition = 'plugins_public/tests/data/kyverno/component-definition.json' + c2p_config.pvp_name = 'Kyverno' + c2p_config.result_title = 'Kyverno Assessment Results' + c2p_config.result_description = 'OSCAL Assessment Results from Kyverno' + ``` +1. Select a plugin for supported PVPs (`PluginKyverno`, `PluginOCM`) and create `PluginConfig` object to supply plugin specific properties + ```python + from plugins_public.plugins.kyverno import PluginConfigKyverno, PluginKyverno + config = PluginConfigKyverno() + ``` +1. Create `C2P` and `Plugin` + ```python + c2p = C2P(c2p_config) + plugin = PluginKyverno(config) + ``` +1. Load PVP native results + ```python + policy_report_file = 'plugins_public/tests/data/kyverno/policyreports.wgpolicyk8s.io.yaml' + cluster_policy_report_file = 'plugins_public/tests/data/kyverno/clusterpolicyreports.wgpolicyk8s.io.yaml' + policy_report = yaml.safe_load(pathlib.Path(policy_report_file).open('r')) + cluster_policy = yaml.safe_load(pathlib.Path(cluster_policy_report_file).open('r')) + pvp_raw_result = RawResult(data=policy_report['items'] + cluster_policy['items']) + ``` +1. Call `generate_pvp_result()` of the plugin to get a formatted PVP result + ```python + pvp_result = PluginKyverno().generate_pvp_result(pvp_raw_result) + ``` +1. Create `C2P` and call `result_to_oscal()` to obtain Compliance Assessment Results + ```python + c2p.set_pvp_result(pvp_result) + oscal_assessment_results = c2p.result_to_oscal() + print(oscal_assessment_results.oscal_serialize_json(pretty=True)) + ``` +1. (Optional) you may reformat OSCAL Assessment Results in markdown style. + ``` + c2p tools viewer -ar -cdef ./plugins_public/tests/data/ocm/component-definition.json -o /tmp/assessment_results.md + ``` + +## How to support your own PVP in C2P + +You can create a custom plugin by overriding `PluginSpec` and `PluginConfig`. +`PluginSpec` has two interfaces `generate_pvp_policy` and `generate_pvp_result`. +C2P framework will instantiate `PluginSpec` with `PluginConfig`. + +#### PluginConfig +1. Extend PluginConfig with custom fields as the plugin needs + ```python + from c2p.framework.plugin_spec import PluginSpec + class YourPluginConfig(PluginConfig): + custom_field: str = Field(..., title='Custom field for your plugin') + ``` +1. Extend PluginSpec and define __init__ with YourPluginConfig + ```python + class YourPlugin(PluginSpec): + def __init__(self, config: Optional[YourPluginConfig] = None) -> None: + super().__init__() + self.config = config # work on config + ``` + +#### PluginSpec.generate_pvp_policy +1. `generate_pvp_policy()` in `PluginSpec` accepts one argument `policy: c2p.framework.models.Policy`. + The object has two fields (`rule_sets` and `parameters`). `rule_sets` and `parameters` are a list of Rule_Id, Check_Id, Parameter_Id, Parameter_Value, etc of the components handled by your PVP in OSCAL Component Definition. +1. Implement the logic to generate PVP policy from provided rule_sets and parameters. + ```python + def generate_pvp_policy(self, policy: Policy): + rule_sets: List[RuleSet] = policy.rule_sets + parameters: List[Parameter] = policy.parameters + # generate deliverable policy from rule_sets and parameters + ``` + +#### PluginSpec.generate_pvp_result +1. `generate_pvp_result()` is expected to generate the summarized raw results of your PVP per unit in `PVPResult` format. This unit must be associated with a unique id called Check_Id. For example of [PluginKyverno](/plugins_public/plugins/kyverno.py), Policy Reports is the raw results and are summarized by policy name. + ```python + def generate_pvp_result(self, raw_result: RawResult) -> PVPResult: + pvp_result: PVPResult = PVPResult() + observations: List[ObservationByCheck] = [] -C2P is targeting a plugin architecture to cover not only OCM Policy Framework but also other types of PVPs. -Please go to the docs for each usage. -- [C2P for OCM](/docs/ocm/README.md) -- [C2P for Kyverno](/docs/kyverno/README.md) + polrs = list( + filter( + lambda x: x['apiVersion'] == 'wgpolicyk8s.io/v1alpha2' and x['kind'] == 'PolicyReport', raw_result.data + ) + ) + cpolrs = list( + filter( + lambda x: x['apiVersion'] == 'wgpolicyk8s.io/v1alpha2' and x['kind'] == 'ClusterPolicyReport', + raw_result.data, + ) + ) -## Build at local + results = [] + for polr in polrs: + for result in polr['results']: + results.append(result) + for cpolr in cpolrs: + for result in cpolr['results']: + results.append(result) + + policy_names = list(map(lambda x: x['policy'], results)) # policy_name is used as check_id + policy_names = set(policy_names) + + for policy_name in policy_names: + observation = ObservationByCheck(check_id=policy_name, methods=['AUTOMATED'], collected=get_datetime()) + ``` + +1. The input argument `raw_result` has `data` field that is serialized raw results as dict. You can define your preferable format of the data. C2P Framework will pass PVP native results to plugin with this format. + +#### Publish plugin +1. Put the plugin in plugin directory [/plugins_public/plugins](/plugins_public/plugins) or Python module path when you use C2P. + +## Development + +### Developing +1. Install Python + ``` + $ python --version + Python 3.10.12 + ``` +1. Setup venv + ``` + python -m venv .venv + ``` +1. Install dependant modules + ``` + make install-dev + ``` +1. Enable detect-secret + ``` + pre-commit install + ``` + +### Test ``` -goreleaser release --snapshot --clean +$ make test + +plugins_public/tests/plugins/test_kyverno.py::test_kyverno_pvp_result_to_compliance PASSED [ 25%] +plugins_public/tests/plugins/test_kyverno.py::test_kyverno_compliance_to_policy PASSED [ 50%] +plugins_public/tests/plugins/test_ocm.py::test_ocm_pvp_result_to_compliance PASSED [ 75%] +plugins_public/tests/plugins/test_ocm.py::test_ocm_compliance_to_policy +------------------------------------------------------------------------------------------ live log call ------------------------------------------------------------------------------------------- +2024-04-25 05:31:48 [ INFO] The deliverable policy directory '/var/folders/yx/1mv5rdh53xd93bphsc459ht00000gn/T/tmpxtvpcrpr/deliverable-policy' is not found. Creating... (ocm.py:191) +PASSED [100%] + +======================================================================================== 4 passed in 0.31s ========================================================================================= + +tests/c2p/framework/test_c2p.py::test_result_to_oscal PASSED [ 33%] +tests/c2p/test_cli.py::test_run PASSED [ 66%] +tests/c2p/test_cli.py::test_version PASSED [100%] + +======================================================================================== 3 passed in 0.26s ========================================================================================= ``` -## Test +### Cleanup caches ``` -make test-pkg +make clean ``` \ No newline at end of file diff --git a/c2p/__init__.py b/c2p/__init__.py new file mode 100644 index 0000000..bd26775 --- /dev/null +++ b/c2p/__init__.py @@ -0,0 +1,15 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/c2p/__main__.py b/c2p/__main__.py new file mode 100644 index 0000000..61d3f25 --- /dev/null +++ b/c2p/__main__.py @@ -0,0 +1,26 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import c2p.cli + + +def init() -> None: + """Initialize c2p CLI.""" + if __name__ == '__main__': + c2p.cli.run() + + +init() diff --git a/c2p/cli.py b/c2p/cli.py new file mode 100644 index 0000000..926315c --- /dev/null +++ b/c2p/cli.py @@ -0,0 +1,53 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +from logging import DEBUG +from sys import exit + +from trestle.common import const, log +from trestle.core.commands.command_docs import CommandBase + +from c2p.commands.tools.tools import Tools +from c2p.commands.version import VersionCmd +from c2p.common import logging + +logger = logging.getLogger(__name__) + + +class C2P(CommandBase): + """Bridge Compliance and Policy""" + + subcommands = [ + VersionCmd, + Tools, + ] + + def _init_arguments(self) -> None: + self.add_argument('-v', '--verbose', help=const.DISPLAY_VERBOSE_OUTPUT, action='count', default=0) + + def _validate_and_run(self, args: argparse.ArgumentParser): + if args.verbose > 0: + logging.set_global_logging_levels(DEBUG) + + +def run() -> None: + """Run the c2p cli.""" + log.set_global_logging_levels() + logging.set_global_logging_levels() + logger.debug('Main entry point.') + + exit(C2P().run()) diff --git a/c2p/commands/__init__.py b/c2p/commands/__init__.py new file mode 100644 index 0000000..bd26775 --- /dev/null +++ b/c2p/commands/__init__.py @@ -0,0 +1,15 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/c2p/commands/tools/__init__.py b/c2p/commands/tools/__init__.py new file mode 100644 index 0000000..bd26775 --- /dev/null +++ b/c2p/commands/tools/__init__.py @@ -0,0 +1,15 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/c2p/commands/tools/csv2oscal_cd.py b/c2p/commands/tools/csv2oscal_cd.py new file mode 100644 index 0000000..46cd44b --- /dev/null +++ b/c2p/commands/tools/csv2oscal_cd.py @@ -0,0 +1,70 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import pathlib + +from trestle.common.err import handle_generic_command_exception +from trestle.core.commands.command_docs import CommandBase +from trestle.core.commands.common.return_codes import CmdReturnCodes + +from c2p.common import logging +from c2p.tools.oscal_csv_to_json import OscalCsvToJson + +logger = logging.getLogger(__name__) + + +class Csv2OscalCd(CommandBase): + """Command to generate OSCAL Component Definition from component definition in csv format""" + + name = 'csv-to-oscal-cd' + + def _init_arguments(self) -> None: + self.add_argument( + '-c', + '--config', + type=pathlib.Path, + help='Path to config file if --csv, --title, and -o are not given', + required=False, + ) + self.add_argument('--title', type=str, help='Title of component-definition', required=False) + self.add_argument('--csv', type=pathlib.Path, help='Path to csv file', required=False) + self.add_argument( + '-o', + '--out', + type=pathlib.Path, + help='Path to directory for output of component-definition.json', + required=False, + ) + self.add_argument( + '-i', '--info', action='store_true', help='Print information about a particular task.', required=False + ) + + def _run(self, args: argparse.Namespace) -> int: + octj = OscalCsvToJson() + try: + if args.config != None: + octj.generate(pathlib.Path(args.config)) + elif args.title != None and args.csv != None and args.out != None: + path = octj.generate_config(args.title, args.csv, args.out) + octj.generate(path) + + except Exception as e: + return handle_generic_command_exception( + e, logger, 'Error while performing OSCAL Assessment Results generation' + ) + + return CmdReturnCodes.SUCCESS.value diff --git a/c2p/commands/tools/tools.py b/c2p/commands/tools/tools.py new file mode 100644 index 0000000..2eb79a0 --- /dev/null +++ b/c2p/commands/tools/tools.py @@ -0,0 +1,28 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from trestle.core.commands.command_docs import CommandBase + +from c2p.commands.tools.csv2oscal_cd import Csv2OscalCd +from c2p.commands.tools.viewer import Viewer + + +class Tools(CommandBase): + """Subcommand for tools""" + + name = 'tools' + + subcommands = [Csv2OscalCd, Viewer] diff --git a/c2p/commands/tools/viewer.py b/c2p/commands/tools/viewer.py new file mode 100644 index 0000000..e498246 --- /dev/null +++ b/c2p/commands/tools/viewer.py @@ -0,0 +1,74 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import pathlib + +from trestle.common.err import handle_generic_command_exception +from trestle.core.commands.command_docs import CommandBase +from trestle.core.commands.common.return_codes import CmdReturnCodes +from trestle.oscal.assessment_results import AssessmentResults +from trestle.oscal.component import ComponentDefinition + +from c2p.common import logging +from c2p.tools.viewer import viewer + +logger = logging.getLogger(__name__) + + +class Viewer(CommandBase): + """Command to render OSCAL Assessment Results in markdown""" + + name = 'viewer' + + def _init_arguments(self) -> None: + self.add_argument( + '-ar', + '--assessment-results', + type=pathlib.Path, + help='Path to OSCAL Assessment Results', + required=True, + ) + self.add_argument( + '-cdef', + '--component-definition', + type=pathlib.Path, + help='Path to OSCAL Component Definition', + required=True, + ) + self.add_argument( + '-o', + '--out', + type=pathlib.Path, + help='Path to output file', + required=False, + ) + + def _run(self, args: argparse.Namespace) -> int: + + ar = AssessmentResults.oscal_read(args.assessment_results) + cdef = ComponentDefinition.oscal_read(args.component_definition) + rendered_md = viewer.render(ar, cdef) + try: + if args.out != None: + pathlib.Path(args.out).open('w').write(rendered_md) + else: + self.out(rendered_md) + + except Exception as e: + return handle_generic_command_exception(e, logger, 'Error while performing rendering Assessment Results') + + return CmdReturnCodes.SUCCESS.value diff --git a/c2p/commands/version.py b/c2p/commands/version.py new file mode 100644 index 0000000..320e70c --- /dev/null +++ b/c2p/commands/version.py @@ -0,0 +1,32 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""C2P Version Command.""" +import argparse +from importlib.metadata import version + +from trestle.core.commands.command_docs import CommandBase +from trestle.core.commands.common.return_codes import CmdReturnCodes + + +class VersionCmd(CommandBase): + """Output version info for C2P.""" + + name = 'version' + + def _run(self, _: argparse.Namespace) -> int: + self.out(version('compliance-to-policy')) + return CmdReturnCodes.SUCCESS.value diff --git a/c2p/common/__init__.py b/c2p/common/__init__.py new file mode 100644 index 0000000..bd26775 --- /dev/null +++ b/c2p/common/__init__.py @@ -0,0 +1,15 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/c2p/common/c2p_base_model.py b/c2p/common/c2p_base_model.py new file mode 100644 index 0000000..884f031 --- /dev/null +++ b/c2p/common/c2p_base_model.py @@ -0,0 +1,92 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import json +import pathlib +from typing import Any, Dict, Optional, Type, TypeVar + +import orjson +from pydantic import BaseModel +from pydantic.parse import load_file +from trestle.core.base_model import robust_datetime_serialization + +import c2p.common.err as err + + +class C2PBaseModel(BaseModel): + """Base Model. Serves as wrapper around BaseModel for overriding methods.""" + + class Config: + json_encoders = {datetime.datetime: lambda x: robust_datetime_serialization(x)} + + @classmethod + def read(cls, path: pathlib.Path) -> Optional['C2PBaseModel']: + obj: Dict[str, Any] = {} + try: + obj = load_file( + path, + json_loads=cls.__config__.json_loads, + ) + except Exception as e: + raise err.C2PError(f'Error loading file {path} {str(e)}') + + try: + parsed = cls.parse_obj(obj) + except Exception as e: + raise err.C2PError(f'Error parsing file {path} {str(e)}') + + return parsed + + def serialize_json_bytes(self, pretty: bool = False) -> bytes: + odict = self.dict(by_alias=True, exclude_none=True) + if pretty: + return orjson.dumps(odict, default=self.__json_encoder__, option=orjson.OPT_INDENT_2) # type: ignore + return orjson.dumps(odict, default=self.__json_encoder__) # type: ignore + + +T = TypeVar('T', BaseModel, Any) + + +class C2PBaseDict(Dict[str, T]): + _member_class: Type[T] + + def __init__(self, obj: dict = {}, **kwargs): + if issubclass(self._member_class, BaseModel): + member_dict = {} + for key, value in kwargs.items(): + c = self._member_class(**value) + member_dict[key] = c + for key, value in obj.items(): + c = self._member_class(**value) + member_dict[key] = c + super().__init__(member_dict) + else: + super().__init__(obj, **kwargs) + + def serialize_json_bytes(self, pretty: bool = False) -> bytes: + if pretty: + return orjson.dumps(self, default=self._get_json_encoder(), option=orjson.OPT_INDENT_2) # type: ignore + return orjson.dumps(self, default=self._get_json_encoder()) + + def json(self) -> str: + return json.dumps(self, default=self._get_json_encoder()) + + def _get_json_encoder(self) -> Any: + if issubclass(self._member_class, BaseModel): + return self._member_class.__json_encoder__ + else: + return None diff --git a/c2p/common/err.py b/c2p/common/err.py new file mode 100644 index 0000000..e0062bb --- /dev/null +++ b/c2p/common/err.py @@ -0,0 +1,37 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +class C2PError(RuntimeError): + """ + General framework (non-application) related errors. + + Attributes: + msg (str): Human readable string describing the exception. + """ + + def __init__(self, msg: str): + """Intialization for C2PError. + + Args: + msg (str): The error message + """ + RuntimeError.__init__(self) + self.msg = msg + + def __str__(self) -> str: + """Return C2P error message if asked for a string.""" + return self.msg diff --git a/c2p/common/logging.py b/c2p/common/logging.py new file mode 100644 index 0000000..c6aeb8a --- /dev/null +++ b/c2p/common/logging.py @@ -0,0 +1,47 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import sys + +# Singleton logger instance +_logger = logging.getLogger('c2p') + +FORMATTER_STR = '[%(asctime)s %(levelname)s %(name)s] %(message)s' + + +def set_global_logging_levels(level: int = logging.INFO) -> None: + """Initialise logging. + + Should only be invoked by the CLI classes or similar. + """ + # This line stops default root loggers setup for a python context from logging extra messages. + # DO NOT USE THIS COMMAND directly from an SDK. Handle logs levels based on your own application + _logger.propagate = False + # Remove handlers + _logger.handlers.clear() + # set global level + _logger.setLevel(level) + # Create standard out + handler = logging.StreamHandler(sys.stderr) + handler.setLevel(level) + handler.setFormatter(logging.Formatter(FORMATTER_STR)) + # add ch to logger + _logger.addHandler(handler) + + +def getLogger(name: str) -> logging.Logger: + return logging.getLogger(name) diff --git a/c2p/common/oscal.py b/c2p/common/oscal.py new file mode 100644 index 0000000..d1fe487 --- /dev/null +++ b/c2p/common/oscal.py @@ -0,0 +1,37 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Dict, List + +from trestle.common import const +from trestle.common.common_types import TypeWithParamId, TypeWithParts, TypeWithProps +from trestle.common.list_utils import as_filtered_list, as_list, none_if_empty + + +def is_component_type_validation(component_type: str) -> bool: + return component_type.lower() == 'validation' + + +def get_rule_sets(item: TypeWithProps) -> List[Dict[str, str]]: + """Get all rules found in this items props.""" + # rules is dict containing rule_id and description + rules_dict = {} + for prop in as_list(item.props): + remarks = prop.remarks + if not remarks in rules_dict: + rules_dict[remarks] = {} + rules_dict[remarks][prop.name] = prop.value + return list(map(lambda x: x[1], rules_dict.items())) diff --git a/c2p/common/utils.py b/c2p/common/utils.py new file mode 100644 index 0000000..15b9543 --- /dev/null +++ b/c2p/common/utils.py @@ -0,0 +1,100 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import pathlib +import re +from datetime import datetime, timezone +from typing import Any, List, Union + +from trestle.oscal.component import ComponentDefinition + +from c2p.common import logging + +logger = logging.getLogger('common:utils') + + +class Control: + def __init__(self, control_id, impl_id, component_id): + self.control_id = control_id + self.impl_id = impl_id + self.component_id = component_id + + +class ControlList: + def __init__(self, items: List['Control']): + self.items = items + + def get_control_ids(self) -> List[str]: + def custom_sort(key): + tokens = re.split('(\d+)', key) + return list(map(lambda x: int(x) if x.isdigit() else x, tokens)) + + control_ids = set(map(lambda x: x.control_id, self.items)) + return sorted(list(control_ids), key=custom_sort) + + +def get_control_list(path: str) -> ControlList: + cdef = ComponentDefinition.oscal_read(pathlib.Path(path)) + controls: List[Control] = [] + for component in cdef.components: + for control_impl in component.control_implementations: + control_impl.uuid + for impl_req in control_impl.implemented_requirements: + control = Control(impl_req.control_id, control_impl.uuid, component.uuid) + controls.append(control) + + return ControlList(controls) + + +def load_json_as_dict(path: Union[str, pathlib.Path]) -> Any: + test_te_path: pathlib.Path + if isinstance(path, str): + test_te_path = pathlib.Path(path) + elif isinstance(path, pathlib.Path): + test_te_path = path + else: + return + fh = test_te_path.open('r', encoding='utf8') + return json.load(fh) + + +def get_datetime() -> datetime: + return datetime.utcnow().replace(microsecond=0).replace(tzinfo=timezone.utc) + + +def get_dict_safely(d, key: Union[str, List[str]], default=None): + if isinstance(key, str): + if d is not None and isinstance(d, dict): + return d[key] if key in d else default + else: + return default + else: + if len(key) > 0: + k = key.pop(0) + v = get_dict_safely(d, k, default) + return get_dict_safely(v, key, default) + else: + return d + + +def remove_none(obj): + if isinstance(obj, (list, tuple, set)): + return type(obj)(remove_none(x) for x in obj if x is not None) + elif isinstance(obj, dict): + return type(obj)((remove_none(k), remove_none(v)) for k, v in obj.items() if k is not None and v is not None) + else: + return obj diff --git a/c2p/framework/__init__.py b/c2p/framework/__init__.py new file mode 100644 index 0000000..c81a41f --- /dev/null +++ b/c2p/framework/__init__.py @@ -0,0 +1,21 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pluggy + +LAYER_NAME = 'p2c' +hookimpl = pluggy.HookimplMarker(LAYER_NAME) +hookspec = pluggy.HookspecMarker(LAYER_NAME) diff --git a/c2p/framework/c2p.py b/c2p/framework/c2p.py new file mode 100644 index 0000000..037c1d2 --- /dev/null +++ b/c2p/framework/c2p.py @@ -0,0 +1,211 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pathlib +from typing import Dict, List, Optional + +from pydantic import BaseModel +from trestle import __version__ as TRESTLE_VERSION +from trestle.oscal import OSCAL_VERSION +from trestle.oscal.assessment_results import ( + AssessmentResults, + ImportAp, + Observation, + Result, +) +from trestle.oscal.catalog import Catalog +from trestle.oscal.catalog import Model as CatalogRoot +from trestle.oscal.common import ( + Link, + Metadata, + Property, + RelevantEvidence, + SubjectReference, +) +from trestle.oscal.component import ComponentDefinition +from trestle.oscal.component import Model as ComponentDefinitionRoot +from trestle.oscal.profile import Model as ProfileRoot +from trestle.oscal.profile import Profile + +from c2p.common.oscal import is_component_type_validation +from c2p.common.utils import get_dict_safely +from c2p.framework import oscal_utils +from c2p.framework.models.c2p_config import C2PConfig +from c2p.framework.models.policy import Parameter, Policy, RuleSet +from c2p.framework.models.pvp_result import PVPResult, set_defaults + +RuleId = str + + +class _RuleSet(BaseModel): + effective_rule_id: str + effective_check_id: str + rule_id: str + rule_description: Optional[str] + check_id: Optional[str] + check_description: Optional[str] + raw: Optional[Dict[str, str]] + + +class C2P: + def __init__(self, c2p_config: C2PConfig): + self._c2p_config = c2p_config + if c2p_config.compliance.catalog: + catalog = Catalog.oscal_read(pathlib.Path(c2p_config.compliance.catalog)) + self._catalog_root: CatalogRoot = CatalogRoot(catalog=catalog) + if c2p_config.compliance.profile: + profile = Profile.oscal_read(pathlib.Path(c2p_config.compliance.profile)) + self._profile_root: ProfileRoot = ProfileRoot(profile=profile) + cdef = ComponentDefinition.oscal_read(pathlib.Path(c2p_config.compliance.component_definition)) + self._component_root: ComponentDefinitionRoot = ComponentDefinitionRoot(component_definition=cdef) + + def set_pvp_result(self, pvp_result: PVPResult): + self._c2p_config.pvp_result = pvp_result + + def result_to_oscal(self) -> AssessmentResults: + pvp_result = set_defaults(self._c2p_config.pvp_result) + timestamp = oscal_utils.get_datetime_str() + metadata = Metadata( + title=self._c2p_config.result_title, + oscal_version=OSCAL_VERSION, + version=TRESTLE_VERSION, + last_modified=timestamp, + ) + import_ap = ImportAp(href='https://not-available-for-now') + value = AssessmentResults( + uuid=oscal_utils.uuid(), + metadata=metadata, + import_ap=import_ap, + results=[self._get_result(pvp_result)], + ) + return value + + def get_policy(self) -> Policy: + return Policy(rule_sets=self.get_rule_sets(), parameters=self.get_parameters()) + + def get_rule_sets(self) -> List[RuleSet]: + _rule_sets = self._get_rule_sets() + + def _conv(x: _RuleSet): + return RuleSet( + rule_id=x.effective_rule_id, + rule_description=x.rule_description, + check_id=x.effective_check_id, + check_description=x.check_description, + raw=x.raw, + ) + + return list(map(_conv, _rule_sets)) + + def get_parameters(self) -> List[Parameter]: + return self._get_parameters() + + def _get_rule_sets(self) -> List[_RuleSet]: + rule_sets: List[Dict[str, str]] = [] + for comp in self._component_root.component_definition.components: + if is_component_type_validation(comp.type) and comp.title == self._c2p_config.pvp_name: + rule_sets = oscal_utils.group_props_by_remarks(comp) + + def _conv(x: Dict[str, str]) -> _RuleSet: + return _RuleSet( + rule_id=get_dict_safely(x, 'Rule_Id'), + rule_description=get_dict_safely(x, 'Rule_Description'), + check_id=get_dict_safely(x, 'Check_Id'), + check_description=get_dict_safely(x, 'Check_Description'), + effective_rule_id=get_dict_safely(x, self._c2p_config.compliance.rule_id_column), + effective_check_id=get_dict_safely(x, self._c2p_config.compliance.check_id_column), + raw=x, + ) + + return list(map(_conv, filter(lambda x: 'Rule_Id' in x, rule_sets))) + + def _find_rule_set(self, check_id: str, rule_sets: List[_RuleSet]) -> Optional[_RuleSet]: + return next(filter(lambda x: x.effective_check_id == check_id, rule_sets), None) + + def _get_parameters(self) -> List[Parameter]: + parameters: List[Dict[str, str]] = [] + for component in self._component_root.component_definition.components: + if not is_component_type_validation(component.type): + parameters = oscal_utils.group_props_by_remarks(component) + + def _conv(x: Dict[str, str]) -> Parameter: + return Parameter( + id=get_dict_safely(x, 'Parameter_Id'), + description=get_dict_safely(x, 'Parameter_Description'), + value=get_dict_safely(x, 'Parameter_Value_Alternatives'), + ) + + return list(map(_conv, filter(lambda x: 'Parameter_Id' in x, parameters))) + + def _find_parameter(self, id: str, parameters: List[Parameter]) -> Optional[Parameter]: + return next(filter(lambda x: x.id == id, parameters), None) + + def _get_result(self, pvp_result: PVPResult) -> Result: + """Return result.""" + result = Result( + uuid=oscal_utils.uuid(), + title=self._c2p_config.result_title, + description=self._c2p_config.result_description, + start=oscal_utils.get_datetime_str(), + observations=self._get_observations(pvp_result), + reviewed_controls=oscal_utils.reviewed_controls(self._component_root.component_definition), + ) + if pvp_result.links != None: + result.links = list(map(lambda x: Link(href=x.href, text=x.description), pvp_result.links)) + if self._c2p_config.result_labels != None: + result.props = list(map(lambda x: Property(name='label', value=x), self._c2p_config.result_labels)) + return result + + def _get_observations(self, pvp_result: PVPResult) -> List[Observation]: + rule_sets = self._get_rule_sets() + observations = [] + for observation in pvp_result.observations_by_check: + rule_set = self._find_rule_set(observation.check_id, rule_sets) + if rule_set != None: + subjects = [] + for subject in observation.subjects: + props = [] + oscal_utils.add_prop(props, 'resource-id', subject, ['resource_id']) + oscal_utils.add_prop(props, 'result', subject, ['result']) + oscal_utils.add_prop(props, 'evaluated-on', subject, ['evaluated_on']) + oscal_utils.add_prop(props, 'reason', subject, ['reason']) + s = SubjectReference( + subject_uuid=oscal_utils.uuid(), title=subject.title, type=subject.type, props=props + ) + subjects.append(s) + + relevant_evidences = [] + if observation.relevant_evidences != None: + for rel in observation.relevant_evidences: + relevant_evidences.append(RelevantEvidence(href=rel.href, description=rel.description)) + + props = [] + oscal_utils.add_prop(props, 'assessment-rule-id', rule_set.effective_rule_id, []) + if observation.props != None: + props = props + observation.props + o = Observation( + uuid=oscal_utils.uuid(), + title=observation.title, + description=observation.title, + methods=observation.methods, + props=props, + subjects=subjects, + collected=observation.collected, + ) + if len(relevant_evidences) > 0: + o.relevant_evidence = relevant_evidences + observations.append(o) + return observations diff --git a/c2p/framework/models/__init__.py b/c2p/framework/models/__init__.py new file mode 100644 index 0000000..2c0e86c --- /dev/null +++ b/c2p/framework/models/__init__.py @@ -0,0 +1,19 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from c2p.framework.models.pvp_result import PVPResult +from c2p.framework.models.raw_result import RawResult +from c2p.framework.models.policy import Policy, Parameter, RuleSet diff --git a/c2p/framework/models/c2p_config.py b/c2p/framework/models/c2p_config.py new file mode 100644 index 0000000..bbdae8c --- /dev/null +++ b/c2p/framework/models/c2p_config.py @@ -0,0 +1,59 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from enum import Enum +from typing import Dict, List, Literal, Optional, Union + +from pydantic import Field + +from c2p.common.c2p_base_model import C2PBaseModel +from c2p.framework.models import PVPResult + + +class ComplianceType(str, Enum): + OSCAL = 'oscal' + + +class ComplianceOscal(C2PBaseModel): + type: Literal[ComplianceType.OSCAL] = Field(ComplianceType.OSCAL, title='Compliance Type') + catalog: Optional[str] + profile: Optional[str] + component_definition: Optional[str] + rule_id_column: Optional[str] = Field( + 'Rule_Id', + title='Column name of Rule Id in component-definition', + ) + rule_description_column: Optional[str] = Field( + 'Rule_Description', + title='Column name of Rule Description in component-definition', + ) + check_id_column: Optional[str] = Field( + 'Check_Id', + title='Column name of Check Id in component-definition', + ) + check_description_column: Optional[str] = Field( + 'Check_Description', + title='Column name of Check Description in component-definition', + ) + + +class C2PConfig(C2PBaseModel): + compliance: Optional[Union[ComplianceOscal]] + pvp_result: Optional[PVPResult] + pvp_name: Optional[str] + result_title: Optional[str] + result_description: Optional[str] + result_labels: Optional[List[str]] = None diff --git a/c2p/framework/models/policy.py b/c2p/framework/models/policy.py new file mode 100644 index 0000000..1ec8052 --- /dev/null +++ b/c2p/framework/models/policy.py @@ -0,0 +1,52 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Dict, List, Optional + +from pydantic import Field + +from c2p.common.c2p_base_model import C2PBaseModel + + +class RuleSet(C2PBaseModel): + rule_id: str = Field( + ..., + title='A unique identifier of a policy (desired state)', + ) + rule_description: Optional[str] = Field(title='Rule description') + check_id: str = Field( + ..., + title='A unique identifier used to reference the result of the policy (desired state)', + ) + check_description: Optional[str] + raw: Optional[Dict[str, str]] + + +class Parameter(C2PBaseModel): + id: str = Field( + ..., + title='A unique identifier of a parameter that can be used while PVP Policy generation', + ) + description: Optional[str] + value: str = Field( + ..., + title='The value of the parameter', + ) + + +class Policy(C2PBaseModel): + rule_sets: List[RuleSet] = Field(None) + parameters: List[Parameter] = Field(None) diff --git a/c2p/framework/models/pvp_result.py b/c2p/framework/models/pvp_result.py new file mode 100644 index 0000000..19649e3 --- /dev/null +++ b/c2p/framework/models/pvp_result.py @@ -0,0 +1,132 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from datetime import datetime +from enum import Enum +from typing import List, Optional + +from pydantic import Field + +from c2p.common.c2p_base_model import C2PBaseModel + + +class ResultEnum(str, Enum): + Pass = 'pass' + Failure = 'failure' + Error = 'error' + + +class Property(C2PBaseModel): + """ + An attribute, characteristic, or quality of the containing object expressed as a namespace qualified name/value pair. The value of a property is a simple scalar value, which may be expressed as a list of values. + """ + + name: str = Field( + ..., + description="A textual label that uniquely identifies a specific attribute, characteristic, or quality of the property's containing object.", + title='Property Name', + ) + value: str = Field( + ..., + description='Indicates the value of the attribute, characteristic, or quality.', + title='Property Value', + ) + + +class Link(C2PBaseModel): + """ + A reference to a local or remote resource + """ + + description: str = Field( + ..., + description='A human-readable description of this evidence.', + title='Relevant Evidence Description', + ) + href: str = Field( + ..., + description='A resolvable URL reference to relevant evidence.', + title='Relevant Evidence Reference', + ) + + +class Subject(C2PBaseModel): + """ + A human-oriented identifier reference to a resource. Use type to indicate whether the identified resource is a component, inventory item, location, user, or something else. + """ + + title: str = Field(title='Name of the object') + type: str = Field( + ..., + title='Subject Universally Unique Identifier Reference Type', + ) + resource_id: str = Field(..., title='Subject Universally Unique Identifier Reference') + result: ResultEnum = Field(..., title='Assessment result') + evaluated_on: Optional[datetime] = Field( + None, + title='Evaluated data/time', + description='The date and time the subject was evaluated. If not given, observations_by_check.collected is used.', + ) + reason: Optional[str] = Field(None, title='Reason') + props: Optional[List[Property]] = Field(None) + + +class ObservationByCheck(C2PBaseModel): + """ + Describes an individual observation based on each Check_Id defined in Component Definition. + """ + + title: Optional[str] = Field( + None, + description='The title for this observation for the check item. If not given, check id is used.', + title='Observation Title', + ) + description: Optional[str] = Field( + None, + description='A human-readable description of this assessment observation. If not given, check description is used.', + title='Observation Description', + ) + check_id: str = Field(..., description='Check_Id', title='Check_Id') + methods: List[str] = Field( + ..., + description='Identifies how the observation was made.', + title='Observation Method', + example=['TEST-AUTOMATED'], + ) + subjects: Optional[List[Subject]] = Field(None) + collected: datetime = Field( + ..., + description='The date and time identifying when the finding information was collected.', + title='Collected date/time', + ) + relevant_evidences: Optional[List[Link]] = Field(None) + props: Optional[List[Property]] = Field(None) + + +class PVPResult(C2PBaseModel): + observations_by_check: Optional[List[ObservationByCheck]] = Field(None) + links: Optional[List[Link]] = Field(None) + + +def set_defaults(pvp_result: PVPResult) -> PVPResult: + for observation in pvp_result.observations_by_check: + if observation.description == None: + observation.title = observation.check_id + observation.description = observation.check_id + for subject in observation.subjects: + if subject.evaluated_on == None: + subject.evaluated_on = observation.collected + return pvp_result diff --git a/c2p/framework/models/raw_result.py b/c2p/framework/models/raw_result.py new file mode 100644 index 0000000..a6618b2 --- /dev/null +++ b/c2p/framework/models/raw_result.py @@ -0,0 +1,46 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Any, Dict, Optional + +from pydantic import Field + +from c2p.common.c2p_base_model import C2PBaseModel + + +class Metadata(C2PBaseModel): + """ + Attributes: + filepath: Filepath + """ + + filepath: Optional[str] = Field(None, title='Filepath') + + +class RawResult(C2PBaseModel): + """ + + Attributes: + metadata: Metadata + data: Data + additional_props: Additional properties + """ + + metadata: Metadata = Field(Metadata()) + data: Any = Field(title='Serialized raw results (JSON, YAML) as dict object') + additional_props: Optional[Dict[str, Any]] = Field( + {}, title='Additional properties', description='Add any information in key-value format if required.' + ) diff --git a/c2p/framework/oscal_utils.py b/c2p/framework/oscal_utils.py new file mode 100644 index 0000000..9a68561 --- /dev/null +++ b/c2p/framework/oscal_utils.py @@ -0,0 +1,118 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from datetime import datetime, timezone +from enum import Enum +from typing import Any, Dict, List, Union +from uuid import uuid4 + +from pydantic import BaseModel +from trestle.common.common_types import TypeWithProps +from trestle.common.list_utils import as_list +from trestle.oscal.assessment_results import ( + ControlSelection, + ReviewedControls, + SelectControlById, +) +from trestle.oscal.common import Property +from trestle.oscal.component import ComponentDefinition + +from c2p.common.oscal import is_component_type_validation + + +def uuid() -> str: + """Return uuid.""" + return str(uuid4()) + + +def group_props_by_remarks(item: TypeWithProps) -> List[Dict[str, str]]: + """Group props by remarks and return as dict of [remark, prop].""" + grouped = {} + for prop in as_list(item.props): + remarks = prop.remarks + if not remarks in grouped: + grouped[remarks] = {} + grouped[remarks][prop.name] = prop.value + return list(map(lambda x: x[1], grouped.items())) + + +def reviewed_controls(component_definition: ComponentDefinition) -> ReviewedControls: + """Return reviewed controls.""" + control_selections = [] + for component in component_definition.components: + if is_component_type_validation(component.type): + continue + for control_impl in component.control_implementations: + selectControls = [] + for impl_req in control_impl.implemented_requirements: + statement_ids = [] + for stmt in impl_req.statements if impl_req.statements != None else []: + statement_ids.append(stmt.statement_id) + selectControl = SelectControlById(control_id=impl_req.control_id, statement_ids=statement_ids) + selectControls.append(selectControl) + control_selections.append(ControlSelection(include_controls=selectControls)) + rval = ReviewedControls(control_selections=control_selections) + return rval + + +def add_prop(props: List[Property], name: str, data: Union[str, Dict, BaseModel], keys: List[str]) -> None: + try: + if isinstance(data, str): + value = data + else: + if isinstance(data, BaseModel): + data = data.dict() + value = get_value(data, keys) + if value == None: + return None + prop = Property(name=normalize(name), value=whitespace(value)) + props.append(prop) + return prop + except KeyError: + return None + + +def get_value(data: Dict, keys: List[str]) -> Any: + """Descend yaml layers to get value for order list of keys.""" + try: + value = data + for key in keys: + value = value[key] + if isinstance(value, Enum): + value = value.value + if isinstance(value, datetime): + value = value.isoformat() + except KeyError: + raise KeyError + return value + + +def whitespace(text: str) -> str: + """Replace line ends with blanks.""" + return str(text).replace('\n', ' ') + + +def normalize(text: str) -> str: + """Replace slashes with underscores.""" + return text.replace('/', '_') + + +def get_datetime() -> datetime: + return datetime.utcnow().replace(microsecond=0).replace(tzinfo=timezone.utc) + + +def get_datetime_str() -> str: + return get_datetime().isoformat() diff --git a/c2p/framework/plugin_spec.py b/c2p/framework/plugin_spec.py new file mode 100644 index 0000000..f562dfe --- /dev/null +++ b/c2p/framework/plugin_spec.py @@ -0,0 +1,37 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from abc import ABC, abstractmethod +from typing import Any + +from pydantic import BaseModel + +from c2p.framework.models.policy import Policy +from c2p.framework.models.pvp_result import PVPResult +from c2p.framework.models.raw_result import RawResult + +PluginConfig = BaseModel + + +class PluginSpec(ABC): + + @abstractmethod + def generate_pvp_result(self, raw_result: RawResult) -> PVPResult: + pass + + @abstractmethod + def generate_pvp_policy(self, policy: Policy) -> Any: + pass diff --git a/c2p/tools/__init__.py b/c2p/tools/__init__.py new file mode 100644 index 0000000..bd26775 --- /dev/null +++ b/c2p/tools/__init__.py @@ -0,0 +1,15 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/c2p/tools/oscal_csv_to_json.py b/c2p/tools/oscal_csv_to_json.py new file mode 100644 index 0000000..f98e947 --- /dev/null +++ b/c2p/tools/oscal_csv_to_json.py @@ -0,0 +1,70 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import configparser +import pathlib +from textwrap import dedent +from typing import Optional + +import trestle.common.const as const +from trestle.common.err import TrestleError +from trestle.tasks.base_task import TaskOutcome +from trestle.tasks.csv_to_oscal_cd import CsvToOscalComponentDefinition + +from c2p.common.logging import getLogger + +logger = getLogger(__name__) + + +class OscalCsvToJson: + def __init__(self) -> None: + pass + + def generate_config(self, title: str, csv_path: pathlib.Path, output_path: pathlib.Path) -> pathlib.Path: + path = output_path / 'csv-to-oscal-cd.config' + with open(path.as_posix(), 'w') as file: + data = f""" + [task.csv-to-oscal-cd] + + title = {title} + version = 1.0 + csv-file = {csv_path.as_posix()} + output-dir = {output_path.as_posix()} + """ + file.write(dedent(data)) + return path + + def generate(self, config_path: pathlib.Path): + config = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation()) + config.read_file(config_path.open('r', encoding=const.FILE_ENCODING)) + config_section: Optional[configparser.SectionProxy] = None + section_label = 'task.csv-to-oscal-cd' + if section_label in config.sections(): + config_section = config[section_label] + else: + logger.warning( + f'Config file was not configured with the appropriate section for the task: "[{section_label}]"' + ) + task = CsvToOscalComponentDefinition(config_section) + simulate_result = task.simulate() + if not (simulate_result == TaskOutcome.SIM_SUCCESS): + raise TrestleError(f'Task {section_label} reported a {simulate_result}') + + actual_result = task.execute() + if not (actual_result == TaskOutcome.SUCCESS): + raise TrestleError(f'Task {section_label} reported a {actual_result}') + + logger.info(f'Task: {section_label} executed successfully.') diff --git a/c2p/tools/viewer/__init__.py b/c2p/tools/viewer/__init__.py new file mode 100644 index 0000000..3242b47 --- /dev/null +++ b/c2p/tools/viewer/__init__.py @@ -0,0 +1,17 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from c2p.tools.viewer.template import TEMPLATE diff --git a/c2p/tools/viewer/template.py b/c2p/tools/viewer/template.py new file mode 100644 index 0000000..8939e45 --- /dev/null +++ b/c2p/tools/viewer/template.py @@ -0,0 +1,47 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +TEMPLATE = """ +{% for component in components %} +## Component: {{ component.title }} + +{% for control_result in component.control_results %} +#### Result of control {{ control_result.id }}: {{ control_result.description }} + +{% for rule_result in control_result.rule_results %} +{% if rule_result.subjects|length > 0 %} +Rule {{ rule_result.id}}: {{ rule_result.description}} +
Details +{% for subject in rule_result.subjects %} + + - Subject UUID: {{ subject.uuid }} + - Title: {{ subject.title }} + - Result: {{ subject.result}} + - Reason: + ``` + {{ subject.reason }} + ``` +{% endfor %} +
+{% else %} +Rule ID: {{ rule_result.id }} + - No subjects found +{% endif %} +{% endfor %} +--- +{% endfor %} +{% endfor %} +""" diff --git a/c2p/tools/viewer/viewer.py b/c2p/tools/viewer/viewer.py new file mode 100644 index 0000000..746cd46 --- /dev/null +++ b/c2p/tools/viewer/viewer.py @@ -0,0 +1,113 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import List, Optional + +from jinja2 import Template +from pydantic import BaseModel +from trestle.oscal.assessment_results import AssessmentResults, Observation +from trestle.oscal.common import Property +from trestle.oscal.component import ComponentDefinition, DefinedComponent + +from c2p.common.oscal import is_component_type_validation +from c2p.framework.oscal_utils import group_props_by_remarks +from c2p.tools.viewer import TEMPLATE + + +class SubjectResult(BaseModel): + uuid: str + title: str + result: str + reason: str + + +class RuleResult(BaseModel): + id: str + description: str + subjects: List[SubjectResult] = [] + + +class ControlResult(BaseModel): + id: str + rule_results: List[RuleResult] = [] + + +class RenderedComponent(BaseModel): + title: str + control_results: List[ControlResult] = [] + + +def find_observation(observations: List[Observation], check_id) -> Optional[Observation]: + for observation in observations: + for prop in observation.props: + if prop.name == 'assessment-rule-id' and prop.value == check_id: + return observation + return None + + +def get_prop_value(props: List[Property], name): + p = next(filter(lambda x: x.name == name, props), None) + return p.value if p != None else None + + +def get_pass_fail_icon(result): + if result == 'pass': + return ':white_check_mark:' + elif result == 'failure': + return ':x:' + else: + return ':warning:' + + +def render(assessment_results: AssessmentResults, component_definition: ComponentDefinition) -> str: + rule_sets = [] + for component in component_definition.components: + if is_component_type_validation(component.type): + rule_sets = rule_sets + group_props_by_remarks(component) + + components: List[DefinedComponent] = list( + filter(lambda x: not is_component_type_validation(x.type), component_definition.components) + ) + + render_components = [] + for component in components: + rendered_component = RenderedComponent(title=component.title) + for control_imple in component.control_implementations: + for imple_req in control_imple.implemented_requirements: + control_id = imple_req.control_id + control_result = ControlResult(id=control_id) + for prop in filter(lambda x: x.name == 'Rule_Id', imple_req.props): + rule_id = prop.value + rule_set = next(filter(lambda x: x['Rule_Id'] == rule_id, rule_sets), None) + if rule_set != None: + rule_result = RuleResult(id=rule_id, description=rule_set['Check_Description']) + o = find_observation(assessment_results.results[0].observations, rule_set['Check_Id']) + if o != None: + for subject in o.subjects: + result = get_prop_value(subject.props, 'result') + result = f'{result} {get_pass_fail_icon(result)}' + reason = get_prop_value(subject.props, 'reason') + sr = SubjectResult( + uuid=subject.subject_uuid, title=subject.title, result=result, reason=reason + ) + rule_result.subjects.append(sr) + control_result.rule_results.append(rule_result) + rendered_component.control_results.append(control_result) + render_components.append(rendered_component) + + tp = Template(source=TEMPLATE) + rendered = tp.render(components=render_components) + return rendered diff --git a/docs/public/images/assessment-results-md.kyverno.jpg b/docs/public/images/assessment-results-md.kyverno.jpg new file mode 100644 index 0000000000000000000000000000000000000000..42a553aa3ca0b0d04d9e70c8d16b783c4311c4d1 GIT binary patch literal 82472 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%0D3m=xHIxd?0 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 U{B48(>wfTc2tZ!w{qgaC0DYs3ZvX%Q literal 0 HcmV?d00001 diff --git a/docs/public/kyverno.md b/docs/public/kyverno.md new file mode 100644 index 0000000..9ffde2f --- /dev/null +++ b/docs/public/kyverno.md @@ -0,0 +1,63 @@ +## Plugin for Kyverno + +#### Prerequisite +- Install KinD and Kyverno 1.10 + +#### Example usage of C2P + +1. Generate Kyverno Policy (C2P Compliance to Policy) + ``` + python samples_public/kyverno/compliance_to_policy.py -o /tmp/deliverable-policy + ``` + E.g. + ``` + $ python samples_public/kyverno/compliance_to_policy.py -o /tmp/deliverable-policy + + tree /tmp/deliverable-policy + disallow-capabilities + - disallow-capabilities.yaml + allowed-base-images + - 02-setup-cm.yaml + - allowed-base-images.yaml + ``` +1. Deploy the generated policies + ``` + kubectl apply -R -f /tmp/deliverable-policy + ``` + E.g. + ``` + $ kubectl apply -R -f /tmp/deliverable-policy + namespace/platform created + configmap/baseimages created + Warning: Validation failure actions enforce/audit are deprecated, use Enforce/Audit instead. + clusterpolicy.kyverno.io/allowed-base-images created + clusterpolicy.kyverno.io/disallow-capabilities created + ``` +1. Check policy results + ``` + $ kubectl get policyreport,clusterpolicyreport -A + NAMESPACE NAME PASS FAIL WARN ERROR SKIP AGE + kube-system policyreport.wgpolicyk8s.io/cpol-allowed-base-images 0 12 0 0 0 19s + kube-system policyreport.wgpolicyk8s.io/cpol-disallow-capabilities 9 2 0 0 0 19s + kyverno policyreport.wgpolicyk8s.io/cpol-allowed-base-images 0 18 0 0 0 9s + kyverno policyreport.wgpolicyk8s.io/cpol-disallow-capabilities 18 0 0 0 0 9s + local-path-storage policyreport.wgpolicyk8s.io/cpol-allowed-base-images 0 3 0 0 0 16s + local-path-storage policyreport.wgpolicyk8s.io/cpol-disallow-capabilities 3 0 0 0 0 16s + ``` +1. Collect policy/cluster policy reports as PVP Raw results + ``` + kubectl get policyreport -A -o yaml > /tmp/policyreports.wgpolicyk8s.io.yaml + kubectl get clusterpolicyreport -o yaml > /tmp/clusterpolicyreports.wgpolicyk8s.io.yaml + ``` +1. Generate Assessment Result (C2P Result to Compliance) + ``` + python samples_public/kyverno/result_to_compliance.py \ + -polr /tmp/policyreports.wgpolicyk8s.io.yaml \ + -cpolr /tmp/clusterpolicyreports.wgpolicyk8s.io.yaml \ + > /tmp/assessment_results.json + ``` +1. OSCAL Assessment Results is not human readable format. You can see the merged report in markdown by a quick viewer. + ``` + c2p tools viewer -ar /tmp/assessment_results.json -cdef ./plugins_public/tests/data/kyverno/component-definition.json -o /tmp/assessment_results.md + ``` + ![assessment-results-md.kyverno.jpg](/docs/public/images/assessment-results-md.kyverno.jpg) \ No newline at end of file diff --git a/docs/public/ocm.md b/docs/public/ocm.md new file mode 100644 index 0000000..3e696b5 --- /dev/null +++ b/docs/public/ocm.md @@ -0,0 +1,194 @@ +## Plugin for OCM + +#### Prerequisite +- Install KinD and setup Open Cluster Management Hub cluster and managed clusters ([Setup OCM](#setup-ocm)) + +#### Example usage of C2P + +1. Generate OCM Policy (C2P Compliance to Policy) + ``` + python samples_public/ocm/compliance_to_policy.py -o /tmp/deliverable-policy + ``` + E.g. + ``` + $ python samples_public/ocm/compliance_to_policy.py + + tree /tmp/deliverable-policy + parameters.yaml + policy-high-scan + - compliance-high-scan + - ScanSettingBinding.high.0.yaml + - policy-generator.yaml + - kustomization.yaml + - compliance-suite-high + - ComplianceSuite.high.0.yaml + - compliance-suite-high-results + - ComplianceCheckResult.noname.0.yaml + policy-deployment + - policy-generator.yaml + - kustomization.yaml + - policy-nginx-deployment + - Deployment.nginx-deployment.0.yaml + policy-disallowed-roles + - policy-disallowed-roles-sample-role + - Role.noname.0.yaml + - policy-generator.yaml + - kustomization.yaml + policy-generator.yaml + ``` +1. Deploy the generated policies + ``` + kustomize build --enable-alpha-plugins /tmp/deliverable-policy | kubectl apply -f - + ``` + E.g. + ``` + $ kubectl apply -R -f /tmp/deliverable-policy + namespace/platform created + configmap/baseimages created + Warning: Validation failure actions enforce/audit are deprecated, use Enforce/Audit instead. + clusterpolicy.kyverno.io/allowed-base-images created + clusterpolicy.kyverno.io/disallow-capabilities created + ``` +1. Check policy statuses at hub cluster + ``` + $ kubectl get policy -A + NAMESPACE NAME REMEDIATION ACTION COMPLIANCE STATE AGE + c2p policy-deployment inform NonCompliant 55s + c2p policy-disallowed-roles inform Compliant 55s + c2p policy-high-scan inform NonCompliant 55s + cluster1 c2p.policy-deployment inform NonCompliant 54s + cluster1 c2p.policy-disallowed-roles inform Compliant 54s + cluster1 c2p.policy-high-scan inform NonCompliant 54s + cluster2 c2p.policy-deployment inform NonCompliant 54s + cluster2 c2p.policy-disallowed-roles inform Compliant 54s + cluster2 c2p.policy-high-scan inform NonCompliant 54s + ``` +1. Collect policies as PVP Raw results + ``` + kubectl get policy -A -o yaml > /tmp/policies.policy.open-cluster-management.io.yaml + kubectl get placementdecisions -A -o yaml > /tmp/placementdecisions.cluster.open-cluster-management.io.yaml + kubectl get policysets -A -o yaml > /tmp/policysets.policy.open-cluster-management.io.yaml + ``` +1. Generate Assessment Result (C2P Result to Compliance) + ``` + python samples_public/ocm/result_to_compliance.py \ + -p /tmp/policies.policy.open-cluster-management.io.yaml \ + > /tmp/assessment_results.json + ``` +1. OSCAL Assessment Results is not human readable format. You can see the merged report in markdown by a quick viewer. + ``` + c2p tools viewer -ar /tmp/assessment_results.json -cdef ./plugins_public/tests/data/ocm/component-definition.json -o /tmp/assessment_results.md + ``` + ![assessment-results-md.ocm.jpg](/docs/public/images/assessment-results-md.ocm.jpg) + +## Setup OCM +1. Prerequisite + - kind + ``` + $ kind version + kind v0.19.0 go1.20.4 darwin/arm64 + ``` + - clusteradm + ``` + $ clusteradm version + client version :v0.8.1-0-g3aea9c5 + server release version :v1.26.0 + default bundle version :0.13.1 + ``` +1. Create 3 KinD clusters (hub, cluster1 and 2) + ``` + kind create cluster --name hub --image kindest/node:v1.26.0 --wait 5m + kind create cluster --name cluster1 --image kindest/node:v1.26.0 --wait 5m + kind create cluster --name cluster2 --image kindest/node:v1.26.0 --wait 5m + ``` +1. Install OCM Hub + ``` + kubectl config use-context kind-hub + clusteradm init --wait + ``` +1. Join clusters to Hub + ``` + kubectl config use-context kind-hub + token=`clusteradm get token | head -n 1 | clusteradm get token | head -n 1 | cut -f 2 -d "="` + server=`kubectl config view --minify -o=jsonpath='{.clusters[0].cluster.server}'` + kubectl config use-context kind-cluster1 + clusteradm join --hub-token $token --hub-apiserver $server --cluster-name cluster1 --force-internal-endpoint-lookup --wait + kubectl config use-context kind-cluster2 + clusteradm join --hub-token $token --hub-apiserver $server --cluster-name cluster2 --force-internal-endpoint-lookup --wait + kubectl config use-context kind-hub + clusteradm accept --clusters cluster2 + ``` +1. Enable governance-policy-framework + ``` + kubectl config use-context kind-hub + clusteradm install hub-addon --names governance-policy-framework + kubectl -n open-cluster-management wait deployment --all --for=condition=Available --timeout 3m + ``` +1. Deploy synchronization components to manages clusters + ``` + kubectl config use-context kind-hub + clusteradm addon enable --names governance-policy-framework --clusters cluster1,cluster2 + for c in cluster1 cluster2 + do + kubectl -n $c wait managedclusteraddon --all --for=condition=Available --timeout 3m + done + ``` +1. Deploy configuration policy controller to the managed cluster(s) + ``` + kubectl config use-context kind-hub + clusteradm addon enable --names config-policy-controller --clusters cluster1,cluster2 + for c in cluster1 cluster2 + do + kubectl -n $c wait managedclusteraddon --all --for=condition=Available --timeout 3m + done + ``` +1. Labeling "environment=dev" to managed clusters + ``` + kubectl config use-context kind-hub + for c in cluster1 cluster2 + do + kubectl label managedcluster $c environment=dev + done + ``` +1. Create managedclusterset + ``` + kubectl config use-context kind-hub + kubectl apply -f - << EOL + apiVersion: cluster.open-cluster-management.io/v1beta2 + kind: ManagedClusterSet + metadata: + name: myclusterset + spec: + clusterSelector: + labelSelector: + matchExpressions: + - key: environment + operator: In + values: + - dev + selectorType: LabelSelector + EOL + ``` +1. Create "c2p" namespace and bind managed clusters to "c2p" namespace + ``` + kubectl config use-context kind-hub + kubectl create ns c2p + clusteradm clusterset bind myclusterset --namespace c2p + ``` +1. The final cluster configuration + ``` + $ clusteradm get clustersets + + └── + │ ├── + │ ├── 2 ManagedClusters selected + │ ├── [cluster1 cluster2] + └── + │ ├── + │ ├── 2 ManagedClusters selected + │ ├── [cluster1 cluster2] + └── + └── c2p + └── 2 ManagedClusters selected + └── [cluster1 cluster2] + ``` diff --git a/.dockerignore b/go/.dockerignore similarity index 100% rename from .dockerignore rename to go/.dockerignore diff --git a/go/.gitignore b/go/.gitignore new file mode 100644 index 0000000..a644dd5 --- /dev/null +++ b/go/.gitignore @@ -0,0 +1,43 @@ + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin +testbin/* +Dockerfile.cross + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Kubernetes Generated files - skip generated files, except for vendored files + +!vendor/**/zz_generated.* + +# editor and IDE paraphernalia +.idea +*.swp +*.swo +*~ + + +# IDE +.vscode +.idea + +# Output of gorelease +dist + +# ignore output by test +/**/_test + +# +policy-collection +out +work +kubeconfig.* \ No newline at end of file diff --git a/.golangci.yaml b/go/.golangci.yaml similarity index 100% rename from .golangci.yaml rename to go/.golangci.yaml diff --git a/.goreleaser.yaml b/go/.goreleaser.yaml similarity index 100% rename from .goreleaser.yaml rename to go/.goreleaser.yaml diff --git a/Dockerfile b/go/Dockerfile similarity index 100% rename from Dockerfile rename to go/Dockerfile diff --git a/go/Makefile b/go/Makefile new file mode 100644 index 0000000..7498510 --- /dev/null +++ b/go/Makefile @@ -0,0 +1,324 @@ +# VERSION defines the project version for the bundle. +# Update this value when you upgrade the version of your project. +# To re-generate a bundle for another specific version without changing the standard setup, you can: +# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) +# - use environment variables to overwrite this value (e.g export VERSION=0.0.2) +VERSION ?= 0.0.1 + +# CHANNELS define the bundle channels used in the bundle. +# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable") +# To re-generate a bundle for other specific channels without changing the standard setup, you can: +# - use the CHANNELS as arg of the bundle target (e.g make bundle CHANNELS=candidate,fast,stable) +# - use environment variables to overwrite this value (e.g export CHANNELS="candidate,fast,stable") +ifneq ($(origin CHANNELS), undefined) +BUNDLE_CHANNELS := --channels=$(CHANNELS) +endif + +# DEFAULT_CHANNEL defines the default channel used in the bundle. +# Add a new line here if you would like to change its default config. (E.g DEFAULT_CHANNEL = "stable") +# To re-generate a bundle for any other default channel without changing the default setup, you can: +# - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable) +# - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable") +ifneq ($(origin DEFAULT_CHANNEL), undefined) +BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) +endif +BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) + +# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images. +# This variable is used to construct full image tags for bundle and catalog images. +# +# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both +# github.com/compliance-to-policy-bundle:$VERSION and github.com/compliance-to-policy-catalog:$VERSION. +IMAGE_TAG_BASE ?= github.com/compliance-to-policy + +# BUNDLE_IMG defines the image:tag used for the bundle. +# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=/:) +BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION) + +# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command +BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) + +# USE_IMAGE_DIGESTS defines if images are resolved via tags or digests +# You can enable this value if you would like to use SHA Based Digests +# To enable set flag to true +USE_IMAGE_DIGESTS ?= false +ifeq ($(USE_IMAGE_DIGESTS), true) + BUNDLE_GEN_FLAGS += --use-image-digests +endif + +# Image URL to use all building/pushing image targets +IMG ?= controller:latest +# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. +ENVTEST_K8S_VERSION = 1.25.0 + +# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) +ifeq (,$(shell go env GOBIN)) +GOBIN=$(shell go env GOPATH)/bin +else +GOBIN=$(shell go env GOBIN) +endif + +# Setting SHELL to bash allows bash commands to be executed by recipes. +# Options are set to exit when a recipe line exits non-zero or a piped command fails. +SHELL = /usr/bin/env bash -o pipefail +.SHELLFLAGS = -ec + +GOOS ?= darwin +GOARCH ?= arm64 +GIT_TAG := $(shell git describe --tags --abbrev=0) +VERSION_FROM_GIT_TAG := $(shell echo "$(GIT_TAG)" | sed 's/^go\///') +DIRTY := $(shell [ -n "$(git status -s)" ] && echo '-snapshot') +REPO_NAME := $(shell git remote get-url origin | sed -r 's/.*:(.*)\.git/\1/') +VERSIONED_SUFFIX := $(if $(DIRTY),$(VERSION_FROM_GIT_TAG)_$(GOOS)_$(GOARCH),$(VERSION_FROM_GIT_TAG)_SNAPSHOT_$(GOOS)_$(GOARCH)) + +repo_name: + echo $(REPO_NAME) + +.PHONY: all +all: build + +.PHONY: build +build: + GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o ./bin/c2pcli_$(VERSIONED_SUFFIX) ./cmd/c2pcli + +.PHONY: test +test: + go test ./pkg/... -coverprofile cover.out + +artifact: build + mkdir -p ./dist/artifacts + tar zcvf ./dist/artifacts/c2pcli_$(VERSIONED_SUFFIX).tar.gz -C ./bin c2pcli_$(VERSIONED_SUFFIX) + shasum -a 256 ./dist/artifacts/c2pcli_$(VERSIONED_SUFFIX).tar.gz > ./dist/artifacts/c2pcli_$(VERSIONED_SUFFIX).sha256 + +# echo $PAT | gh auth login --with-token -h github.com +release: GITHUB_HOST ?= github.com +release: artifact + @(gh release --repo $(GITHUB_HOST)/$(REPO_NAME) view $(GIT_TAG) ;\ + if [[ "$$?" != "0" ]];then \ + echo create release $(GIT_TAG) ;\ + gh release --repo $(GITHUB_HOST)/$(REPO_NAME) create $(GIT_TAG) --generate-notes ;\ + fi) + gh release --repo $(GITHUB_HOST)/$(REPO_NAME) upload $(GIT_TAG) ./dist/artifacts/c2pcli_$(VERSIONED_SUFFIX).* + +## OLM + +##@ General + +# The help target prints out all targets with their descriptions organized +# beneath their categories. The categories are represented by '##@' and the +# target descriptions by '##'. The awk commands is responsible for reading the +# entire set of makefiles included in this invocation, looking for lines of the +# file as xyz: ## something, and then pretty-format the target and help. Then, +# if there's a line with ##@ something, that gets pretty-printed as a category. +# More info on the usage of ANSI control characters for terminal formatting: +# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters +# More info on the awk command: +# http://linuxcommand.org/lc3_adv_awk.php + +.PHONY: help +help: ## Display this help. + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +##@ Development + +.PHONY: manifests +manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. + $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases + +.PHONY: generate +generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. + $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." + +.PHONY: fmt +fmt: ## Run go fmt against code. + go fmt ./... + +.PHONY: vet +vet: ## Run go vet against code. + go vet ./... + +.PHONY: test-controllers +test-controllers: manifests generate fmt vet envtest ## Run tests. + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./controllers/... -coverprofile cover.controllers.out -p=1 + +##@ Build + +.PHONY: build-controllers +build-controllers: generate fmt vet ## Build manager binary. + go build -o bin/manager main.go + +.PHONY: run +run: manifests generate fmt vet ## Run a controller from your host. + go run ./main.go + +# If you wish built the manager image targeting other platforms you can use the --platform flag. +# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. +# More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +.PHONY: docker-build +docker-build: test-controllers ## Build docker image with the manager. + docker build -t ${IMG} . + +.PHONY: docker-push +docker-push: ## Push docker image with the manager. + docker push ${IMG} + +# PLATFORMS defines the target platforms for the manager image be build to provide support to multiple +# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: +# - able to use docker buildx . More info: https://docs.docker.com/build/buildx/ +# - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +# - be able to push the image for your registry (i.e. if you do not inform a valid value via IMG=> than the export will fail) +# To properly provided solutions that supports more than one platform you should use this option. +PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le +.PHONY: docker-buildx +docker-buildx: test-controllers ## Build and push docker image for the manager for cross-platform support + # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile + sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross + - docker buildx create --name project-v3-builder + docker buildx use project-v3-builder + - docker buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross + - docker buildx rm project-v3-builder + rm Dockerfile.cross + +##@ Deployment + +ifndef ignore-not-found + ignore-not-found = false +endif + +.PHONY: install +install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. + $(KUSTOMIZE) build config/crd | kubectl apply -f - + +.PHONY: uninstall +uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. + $(KUSTOMIZE) build config/crd | kubectl delete --ignore-not-found=$(ignore-not-found) -f - + +## For development in a non OCM Hub +.PHONY: install-ocm-related-crds +install-ocm-related-crds: + kubectl apply -f config/ocm + +.PHONY: uninstall-ocm-related-crds +uninstall-ocm-related-crds: + kubectl delete --ignore-not-found=$(ignore-not-found) -f config/ocm + +.PHONY: deploy +deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. + cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} + $(KUSTOMIZE) build config/default | kubectl apply -f - + +.PHONY: undeploy +undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. + $(KUSTOMIZE) build config/default | kubectl delete --ignore-not-found=$(ignore-not-found) -f - + +.PHONY: get-policy-resources +get-policy-resources: + kubectl get policy,placementrule,placementbinding + +.PHONY: delete-policy-resources +delete-all-policy-resources: + kubectl delete policy,placementrule,placementbinding --all + +##@ Build Dependencies + +## Location to install dependencies to +LOCALBIN ?= $(shell pwd)/bin +$(LOCALBIN): + mkdir -p $(LOCALBIN) + +## Tool Binaries +KUSTOMIZE ?= $(LOCALBIN)/kustomize +CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen +ENVTEST ?= $(LOCALBIN)/setup-envtest + +## Tool Versions +KUSTOMIZE_VERSION ?= v4.5.7 +CONTROLLER_TOOLS_VERSION ?= v0.10.0 + +KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" +.PHONY: kustomize +kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. +$(KUSTOMIZE): $(LOCALBIN) + test -s $(LOCALBIN)/kustomize || { curl -Ss $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); } + +.PHONY: controller-gen +controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. +$(CONTROLLER_GEN): $(LOCALBIN) + test -s $(LOCALBIN)/controller-gen || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) + +.PHONY: envtest +envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. +$(ENVTEST): $(LOCALBIN) + test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest + +.PHONY: bundle +bundle: manifests kustomize ## Generate bundle manifests and metadata, then validate generated files. + operator-sdk generate kustomize manifests -q + cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) + $(KUSTOMIZE) build config/manifests | operator-sdk generate bundle $(BUNDLE_GEN_FLAGS) + operator-sdk bundle validate ./bundle + +.PHONY: bundle-build +bundle-build: ## Build the bundle image. + docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) . + +.PHONY: bundle-push +bundle-push: ## Push the bundle image. + $(MAKE) docker-push IMG=$(BUNDLE_IMG) + +.PHONY: opm +OPM = ./bin/opm +opm: ## Download opm locally if necessary. +ifeq (,$(wildcard $(OPM))) +ifeq (,$(shell which opm 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(OPM)) ;\ + OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ + curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.23.0/$${OS}-$${ARCH}-opm ;\ + chmod +x $(OPM) ;\ + } +else +OPM = $(shell which opm) +endif +endif + +# A comma-separated list of bundle images (e.g. make catalog-build BUNDLE_IMGS=example.com/operator-bundle:v0.1.0,example.com/operator-bundle:v0.2.0). +# These images MUST exist in a registry and be pull-able. +BUNDLE_IMGS ?= $(BUNDLE_IMG) + +# The image tag given to the resulting catalog image (e.g. make catalog-build CATALOG_IMG=example.com/operator-catalog:v0.2.0). +CATALOG_IMG ?= $(IMAGE_TAG_BASE)-catalog:v$(VERSION) + +# Set CATALOG_BASE_IMG to an existing catalog image tag to add $BUNDLE_IMGS to that image. +ifneq ($(origin CATALOG_BASE_IMG), undefined) +FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG) +endif + +# Build a catalog image by adding bundle images to an empty catalog using the operator package manager tool, 'opm'. +# This recipe invokes 'opm' in 'semver' bundle add mode. For more information on add modes, see: +# https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator +.PHONY: catalog-build +catalog-build: opm ## Build a catalog image. + $(OPM) index add --container-tool docker --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT) + +# Push the catalog image. +.PHONY: catalog-push +catalog-push: ## Push a catalog image. + $(MAKE) docker-push IMG=$(CATALOG_IMG) + +### +.PHONY: compose-v2 +compose-v2: bin/compose-v2.linux_amd64 bin/compose-v2.darwin_amd64 bin/compose-v2.darwin_arm64 + +bin/compose-v2.linux_amd64: + GOOS=linux GOARCH=amd64 go build -o bin/compose-v2.linux_amd64 ./cmd/compose-v2 + +bin/compose-v2.darwin_amd64: + GOOS=darwin GOARCH=amd64 go build -o bin/compose-v2.darwin_amd64 ./cmd/compose-v2 + +bin/compose-v2.darwin_arm64: + GOOS=darwin GOARCH=arm64 go build -o bin/compose-v2.darwin_arm64 ./cmd/compose-v2 + +bin/compose-v2.%.gz: bin/compose-v2.% + gzip ./bin/compose-v2.$* diff --git a/PROJECT b/go/PROJECT similarity index 73% rename from PROJECT rename to go/PROJECT index ac2e5f9..0f866d0 100644 --- a/PROJECT +++ b/go/PROJECT @@ -5,7 +5,7 @@ plugins: manifests.sdk.operatorframework.io/v2: {} scorecard.sdk.operatorframework.io/v2: {} projectName: compliance-to-policy -repo: github.com/IBM/compliance-to-policy +repo: github.com/oscal-compass/compliance-to-policy/go resources: - api: crdVersion: v1 @@ -14,7 +14,7 @@ resources: domain: github.com group: compliance-to-policy kind: ComplianceDeployment - path: github.com/IBM/compliance-to-policy/api/v1alpha1 + path: github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1 version: v1alpha1 - api: crdVersion: v1 @@ -23,6 +23,6 @@ resources: domain: github.com group: compliance-to-policy kind: ControlReference - path: github.com/IBM/compliance-to-policy/api/v1alpha1 + path: github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1 version: v1alpha1 version: "3" diff --git a/go/README.md b/go/README.md new file mode 100644 index 0000000..4608f2a --- /dev/null +++ b/go/README.md @@ -0,0 +1,52 @@ +# compliance-to-policy +Compliance-to-Policy (C2P) provides the framework to bridge Compliance administration and Policy administration by [OSCAL](https://pages.nist.gov/OSCAL/). OSCAL (Open Security Controls Assessment Language) is a standardized framework developed by NIST for expressing and automating the assessment and management of security controls in machine-readable format (xml, json, yaml) + +![C2P Overview](/go/docs/images/e2e-pm.png) + +## Usage of C2P CLI +``` +$ c2pcli -h +C2P CLI + +Usage: + c2pcli [flags] + c2pcli [command] + +Available Commands: + completion Generate the autocompletion script for the specified shell + help Help about any command + kyverno C2P CLI Kyverno plugin + ocm C2P CLI OCM plugin + version Display version + +Flags: + -h, --help help for c2pcli + +Use "c2pcli [command] --help" for more information about a command. +``` + +C2P is targeting a plugin architecture to cover not only OCM Policy Framework but also other types of PVPs. +Please go to the docs for each usage. +- [C2P for OCM](/go/docs/ocm/README.md) +- [C2P for Kyverno](/go/docs/kyverno/README.md) + +## Build at local +``` +make build +``` +``` +./bin/c2pcli___ -h +``` + +## Test +``` +make test +``` + +## Release +1. Create a git tag of the following format `go/` (e.g. `go/v0.1.2`) +1. Run release command + ``` + echo $PAT | gh auth login --with-token -h github.com + make release + ``` \ No newline at end of file diff --git a/api/v1alpha1/checkpolicy_types.go b/go/api/v1alpha1/checkpolicy_types.go similarity index 100% rename from api/v1alpha1/checkpolicy_types.go rename to go/api/v1alpha1/checkpolicy_types.go diff --git a/api/v1alpha1/compliancedeployment_types.go b/go/api/v1alpha1/compliancedeployment_types.go similarity index 100% rename from api/v1alpha1/compliancedeployment_types.go rename to go/api/v1alpha1/compliancedeployment_types.go diff --git a/api/v1alpha1/compliancereport_types.go b/go/api/v1alpha1/compliancereport_types.go similarity index 97% rename from api/v1alpha1/compliancereport_types.go rename to go/api/v1alpha1/compliancereport_types.go index d0f144f..df5bddb 100644 --- a/api/v1alpha1/compliancereport_types.go +++ b/go/api/v1alpha1/compliancereport_types.go @@ -17,7 +17,7 @@ limitations under the License. package v1alpha1 import ( - wgpolicyk8sv1alpha2 "github.com/IBM/compliance-to-policy/controllers/wgpolicyk8s.io/v1alpha2" + wgpolicyk8sv1alpha2 "github.com/oscal-compass/compliance-to-policy/go/controllers/wgpolicyk8s.io/v1alpha2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/api/v1alpha1/controlreference_common_types.go b/go/api/v1alpha1/controlreference_common_types.go similarity index 100% rename from api/v1alpha1/controlreference_common_types.go rename to go/api/v1alpha1/controlreference_common_types.go diff --git a/api/v1alpha1/controlreference_types.go b/go/api/v1alpha1/controlreference_types.go similarity index 100% rename from api/v1alpha1/controlreference_types.go rename to go/api/v1alpha1/controlreference_types.go diff --git a/api/v1alpha1/controlreferencekcp_types.go b/go/api/v1alpha1/controlreferencekcp_types.go similarity index 100% rename from api/v1alpha1/controlreferencekcp_types.go rename to go/api/v1alpha1/controlreferencekcp_types.go diff --git a/api/v1alpha1/groupversion_info.go b/go/api/v1alpha1/groupversion_info.go similarity index 100% rename from api/v1alpha1/groupversion_info.go rename to go/api/v1alpha1/groupversion_info.go diff --git a/api/v1alpha1/resultcollector_types.go b/go/api/v1alpha1/resultcollector_types.go similarity index 100% rename from api/v1alpha1/resultcollector_types.go rename to go/api/v1alpha1/resultcollector_types.go diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/go/api/v1alpha1/zz_generated.deepcopy.go similarity index 100% rename from api/v1alpha1/zz_generated.deepcopy.go rename to go/api/v1alpha1/zz_generated.deepcopy.go diff --git a/cmd/c2pcli/cmd/cmd.go b/go/cmd/c2pcli/cmd/cmd.go similarity index 88% rename from cmd/c2pcli/cmd/cmd.go rename to go/cmd/c2pcli/cmd/cmd.go index 5bc6c19..72e43c4 100644 --- a/cmd/c2pcli/cmd/cmd.go +++ b/go/cmd/c2pcli/cmd/cmd.go @@ -19,8 +19,8 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/IBM/compliance-to-policy/cmd/c2pcli/options" - "github.com/IBM/compliance-to-policy/cmd/c2pcli/subcommands" + "github.com/oscal-compass/compliance-to-policy/go/cmd/c2pcli/options" + "github.com/oscal-compass/compliance-to-policy/go/cmd/c2pcli/subcommands" ) func New() *cobra.Command { diff --git a/cmd/c2pcli/main.go b/go/cmd/c2pcli/main.go similarity index 94% rename from cmd/c2pcli/main.go rename to go/cmd/c2pcli/main.go index ed58863..0d6109b 100644 --- a/cmd/c2pcli/main.go +++ b/go/cmd/c2pcli/main.go @@ -20,7 +20,7 @@ import ( "fmt" "os" - "github.com/IBM/compliance-to-policy/cmd/c2pcli/cmd" + "github.com/oscal-compass/compliance-to-policy/go/cmd/c2pcli/cmd" "github.com/spf13/cobra" ) diff --git a/cmd/c2pcli/options/options.go b/go/cmd/c2pcli/options/options.go similarity index 100% rename from cmd/c2pcli/options/options.go rename to go/cmd/c2pcli/options/options.go diff --git a/cmd/c2pcli/subcommands/kyverno.go b/go/cmd/c2pcli/subcommands/kyverno.go similarity index 73% rename from cmd/c2pcli/subcommands/kyverno.go rename to go/cmd/c2pcli/subcommands/kyverno.go index 4f8761b..ea7e570 100644 --- a/cmd/c2pcli/subcommands/kyverno.go +++ b/go/cmd/c2pcli/subcommands/kyverno.go @@ -19,10 +19,10 @@ package subcommands import ( "github.com/spf13/cobra" - "github.com/IBM/compliance-to-policy/cmd/c2pcli/options" - oscal2policycmd "github.com/IBM/compliance-to-policy/cmd/kyverno/oscal2policy/cmd" - result2oscalcmd "github.com/IBM/compliance-to-policy/cmd/kyverno/result2oscal/cmd" - toolscmd "github.com/IBM/compliance-to-policy/cmd/kyverno/tools/cmd" + "github.com/oscal-compass/compliance-to-policy/go/cmd/c2pcli/options" + oscal2policycmd "github.com/oscal-compass/compliance-to-policy/go/cmd/kyverno/oscal2policy/cmd" + result2oscalcmd "github.com/oscal-compass/compliance-to-policy/go/cmd/kyverno/result2oscal/cmd" + toolscmd "github.com/oscal-compass/compliance-to-policy/go/cmd/kyverno/tools/cmd" ) func NewKyvernoSubCommand() *cobra.Command { diff --git a/cmd/c2pcli/subcommands/ocm.go b/go/cmd/c2pcli/subcommands/ocm.go similarity index 73% rename from cmd/c2pcli/subcommands/ocm.go rename to go/cmd/c2pcli/subcommands/ocm.go index d3a7cec..2871e1c 100644 --- a/cmd/c2pcli/subcommands/ocm.go +++ b/go/cmd/c2pcli/subcommands/ocm.go @@ -19,10 +19,10 @@ package subcommands import ( "github.com/spf13/cobra" - "github.com/IBM/compliance-to-policy/cmd/c2pcli/options" - oscal2policycmd "github.com/IBM/compliance-to-policy/cmd/ocm/oscal2policy/cmd" - result2oscalcmd "github.com/IBM/compliance-to-policy/cmd/ocm/result2oscal/cmd" - toolscmd "github.com/IBM/compliance-to-policy/cmd/ocm/tools/cmd" + "github.com/oscal-compass/compliance-to-policy/go/cmd/c2pcli/options" + oscal2policycmd "github.com/oscal-compass/compliance-to-policy/go/cmd/ocm/oscal2policy/cmd" + result2oscalcmd "github.com/oscal-compass/compliance-to-policy/go/cmd/ocm/result2oscal/cmd" + toolscmd "github.com/oscal-compass/compliance-to-policy/go/cmd/ocm/tools/cmd" ) func NewOcmSubCommand() *cobra.Command { diff --git a/cmd/decompose/decompose.go b/go/cmd/decompose/decompose.go similarity index 91% rename from cmd/decompose/decompose.go rename to go/cmd/decompose/decompose.go index 169da3c..e247d89 100644 --- a/cmd/decompose/decompose.go +++ b/go/cmd/decompose/decompose.go @@ -20,8 +20,8 @@ import ( "flag" "os" - cmdparse "github.com/IBM/compliance-to-policy/cmd/parse/modules" - "github.com/IBM/compliance-to-policy/pkg/decomposer" + cmdparse "github.com/oscal-compass/compliance-to-policy/go/cmd/parse/modules" + "github.com/oscal-compass/compliance-to-policy/go/pkg/decomposer" cp "github.com/otiai10/copy" "go.uber.org/zap" ) diff --git a/cmd/kyverno/oscal2policy/cmd/cmd.go b/go/cmd/kyverno/oscal2policy/cmd/cmd.go similarity index 86% rename from cmd/kyverno/oscal2policy/cmd/cmd.go rename to go/cmd/kyverno/oscal2policy/cmd/cmd.go index 6c4fa58..2094f74 100644 --- a/cmd/kyverno/oscal2policy/cmd/cmd.go +++ b/go/cmd/kyverno/oscal2policy/cmd/cmd.go @@ -21,10 +21,10 @@ import ( "github.com/spf13/cobra" - "github.com/IBM/compliance-to-policy/cmd/kyverno/oscal2policy/options" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/kyverno" - typec2pcr "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" + "github.com/oscal-compass/compliance-to-policy/go/cmd/kyverno/oscal2policy/options" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/kyverno" + typec2pcr "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" ) func New() *cobra.Command { diff --git a/cmd/ocm/result2oscal/main.go b/go/cmd/kyverno/oscal2policy/main.go similarity index 89% rename from cmd/ocm/result2oscal/main.go rename to go/cmd/kyverno/oscal2policy/main.go index 63064d6..e009b8a 100644 --- a/cmd/ocm/result2oscal/main.go +++ b/go/cmd/kyverno/oscal2policy/main.go @@ -19,7 +19,7 @@ package main import ( "os" - "github.com/IBM/compliance-to-policy/cmd/ocm/result2oscal/cmd" + "github.com/oscal-compass/compliance-to-policy/go/cmd/kyverno/oscal2policy/cmd" ) func main() { diff --git a/cmd/kyverno/oscal2policy/options/options.go b/go/cmd/kyverno/oscal2policy/options/options.go similarity index 100% rename from cmd/kyverno/oscal2policy/options/options.go rename to go/cmd/kyverno/oscal2policy/options/options.go diff --git a/cmd/kyverno/result2oscal/cmd/cmd.go b/go/cmd/kyverno/result2oscal/cmd/cmd.go similarity index 86% rename from cmd/kyverno/result2oscal/cmd/cmd.go rename to go/cmd/kyverno/result2oscal/cmd/cmd.go index 4fcaae7..7a44ada 100644 --- a/cmd/kyverno/result2oscal/cmd/cmd.go +++ b/go/cmd/kyverno/result2oscal/cmd/cmd.go @@ -19,10 +19,10 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/IBM/compliance-to-policy/cmd/kyverno/result2oscal/options" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/kyverno" - typec2pcr "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" + "github.com/oscal-compass/compliance-to-policy/go/cmd/kyverno/result2oscal/options" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/kyverno" + typec2pcr "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" ) func New() *cobra.Command { diff --git a/cmd/kyverno/oscal2policy/main.go b/go/cmd/kyverno/result2oscal/main.go similarity index 89% rename from cmd/kyverno/oscal2policy/main.go rename to go/cmd/kyverno/result2oscal/main.go index 4e4b766..165ede1 100644 --- a/cmd/kyverno/oscal2policy/main.go +++ b/go/cmd/kyverno/result2oscal/main.go @@ -19,7 +19,7 @@ package main import ( "os" - "github.com/IBM/compliance-to-policy/cmd/kyverno/oscal2policy/cmd" + "github.com/oscal-compass/compliance-to-policy/go/cmd/kyverno/result2oscal/cmd" ) func main() { diff --git a/cmd/kyverno/result2oscal/options/options.go b/go/cmd/kyverno/result2oscal/options/options.go similarity index 100% rename from cmd/kyverno/result2oscal/options/options.go rename to go/cmd/kyverno/result2oscal/options/options.go diff --git a/cmd/kyverno/tools/cmd/cmd.go b/go/cmd/kyverno/tools/cmd/cmd.go similarity index 77% rename from cmd/kyverno/tools/cmd/cmd.go rename to go/cmd/kyverno/tools/cmd/cmd.go index ab035d4..ec9585f 100644 --- a/cmd/kyverno/tools/cmd/cmd.go +++ b/go/cmd/kyverno/tools/cmd/cmd.go @@ -19,10 +19,10 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/IBM/compliance-to-policy/cmd/c2pcli/options" - kyvernocmd "github.com/IBM/compliance-to-policy/cmd/kyverno/tools/subcommands/kyverno" - oscal2posturecmd "github.com/IBM/compliance-to-policy/cmd/pvpcommon/oscal2posture/cmd" - "github.com/IBM/compliance-to-policy/pkg" + "github.com/oscal-compass/compliance-to-policy/go/cmd/c2pcli/options" + kyvernocmd "github.com/oscal-compass/compliance-to-policy/go/cmd/kyverno/tools/subcommands/kyverno" + oscal2posturecmd "github.com/oscal-compass/compliance-to-policy/go/cmd/pvpcommon/oscal2posture/cmd" + "github.com/oscal-compass/compliance-to-policy/go/pkg" ) func New() *cobra.Command { diff --git a/cmd/kyverno/tools/options/options.go b/go/cmd/kyverno/tools/options/options.go similarity index 100% rename from cmd/kyverno/tools/options/options.go rename to go/cmd/kyverno/tools/options/options.go diff --git a/cmd/kyverno/tools/subcommands/kyverno/cmd.go b/go/cmd/kyverno/tools/subcommands/kyverno/cmd.go similarity index 97% rename from cmd/kyverno/tools/subcommands/kyverno/cmd.go rename to go/cmd/kyverno/tools/subcommands/kyverno/cmd.go index 94e2314..0cc0077 100644 --- a/cmd/kyverno/tools/subcommands/kyverno/cmd.go +++ b/go/cmd/kyverno/tools/subcommands/kyverno/cmd.go @@ -19,8 +19,8 @@ package kyverno import ( "fmt" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/kyverno" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/kyverno" cp "github.com/otiai10/copy" "github.com/spf13/cobra" "go.uber.org/zap" diff --git a/cmd/kyverno/tools/subcommands/kyverno/options.go b/go/cmd/kyverno/tools/subcommands/kyverno/options.go similarity index 100% rename from cmd/kyverno/tools/subcommands/kyverno/options.go rename to go/cmd/kyverno/tools/subcommands/kyverno/options.go diff --git a/cmd/ocm/oscal2policy/cmd/cmd.go b/go/cmd/ocm/oscal2policy/cmd/cmd.go similarity index 89% rename from cmd/ocm/oscal2policy/cmd/cmd.go rename to go/cmd/ocm/oscal2policy/cmd/cmd.go index c3df179..0f63824 100644 --- a/cmd/ocm/oscal2policy/cmd/cmd.go +++ b/go/cmd/ocm/oscal2policy/cmd/cmd.go @@ -22,10 +22,10 @@ import ( "github.com/spf13/cobra" - "github.com/IBM/compliance-to-policy/cmd/ocm/oscal2policy/options" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/ocm" - typec2pcr "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" + "github.com/oscal-compass/compliance-to-policy/go/cmd/ocm/oscal2policy/options" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/ocm" + typec2pcr "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" ) func New() *cobra.Command { diff --git a/cmd/kyverno/result2oscal/main.go b/go/cmd/ocm/oscal2policy/main.go similarity index 89% rename from cmd/kyverno/result2oscal/main.go rename to go/cmd/ocm/oscal2policy/main.go index adcb3ba..4f95ce6 100644 --- a/cmd/kyverno/result2oscal/main.go +++ b/go/cmd/ocm/oscal2policy/main.go @@ -19,7 +19,7 @@ package main import ( "os" - "github.com/IBM/compliance-to-policy/cmd/kyverno/result2oscal/cmd" + "github.com/oscal-compass/compliance-to-policy/go/cmd/ocm/oscal2policy/cmd" ) func main() { diff --git a/cmd/ocm/oscal2policy/options/options.go b/go/cmd/ocm/oscal2policy/options/options.go similarity index 100% rename from cmd/ocm/oscal2policy/options/options.go rename to go/cmd/ocm/oscal2policy/options/options.go diff --git a/cmd/ocm/result2oscal/cmd/cmd.go b/go/cmd/ocm/result2oscal/cmd/cmd.go similarity index 86% rename from cmd/ocm/result2oscal/cmd/cmd.go rename to go/cmd/ocm/result2oscal/cmd/cmd.go index 87cb305..5bd41ba 100644 --- a/cmd/ocm/result2oscal/cmd/cmd.go +++ b/go/cmd/ocm/result2oscal/cmd/cmd.go @@ -19,10 +19,10 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/IBM/compliance-to-policy/cmd/ocm/result2oscal/options" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/ocm" - typec2pcr "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" + "github.com/oscal-compass/compliance-to-policy/go/cmd/ocm/result2oscal/options" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/ocm" + typec2pcr "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" ) func New() *cobra.Command { diff --git a/cmd/ocm/oscal2policy/main.go b/go/cmd/ocm/result2oscal/main.go similarity index 89% rename from cmd/ocm/oscal2policy/main.go rename to go/cmd/ocm/result2oscal/main.go index 6014769..eb4d483 100644 --- a/cmd/ocm/oscal2policy/main.go +++ b/go/cmd/ocm/result2oscal/main.go @@ -19,7 +19,7 @@ package main import ( "os" - "github.com/IBM/compliance-to-policy/cmd/ocm/oscal2policy/cmd" + "github.com/oscal-compass/compliance-to-policy/go/cmd/ocm/result2oscal/cmd" ) func main() { diff --git a/cmd/ocm/result2oscal/options/options.go b/go/cmd/ocm/result2oscal/options/options.go similarity index 100% rename from cmd/ocm/result2oscal/options/options.go rename to go/cmd/ocm/result2oscal/options/options.go diff --git a/cmd/ocm/tools/cmd/cmd.go b/go/cmd/ocm/tools/cmd/cmd.go similarity index 82% rename from cmd/ocm/tools/cmd/cmd.go rename to go/cmd/ocm/tools/cmd/cmd.go index 5b601a5..229a1e2 100644 --- a/cmd/ocm/tools/cmd/cmd.go +++ b/go/cmd/ocm/tools/cmd/cmd.go @@ -19,9 +19,9 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/IBM/compliance-to-policy/cmd/c2pcli/options" - oscal2posturecmd "github.com/IBM/compliance-to-policy/cmd/pvpcommon/oscal2posture/cmd" - "github.com/IBM/compliance-to-policy/pkg" + "github.com/oscal-compass/compliance-to-policy/go/cmd/c2pcli/options" + oscal2posturecmd "github.com/oscal-compass/compliance-to-policy/go/cmd/pvpcommon/oscal2posture/cmd" + "github.com/oscal-compass/compliance-to-policy/go/pkg" ) func New() *cobra.Command { diff --git a/cmd/ocm/tools/options/options.go b/go/cmd/ocm/tools/options/options.go similarity index 100% rename from cmd/ocm/tools/options/options.go rename to go/cmd/ocm/tools/options/options.go diff --git a/cmd/parse-single/parse-single.go b/go/cmd/parse-single/parse-single.go similarity index 95% rename from cmd/parse-single/parse-single.go rename to go/cmd/parse-single/parse-single.go index 21e771d..1d98cb9 100644 --- a/cmd/parse-single/parse-single.go +++ b/go/cmd/parse-single/parse-single.go @@ -20,7 +20,7 @@ import ( "flag" "os" - "github.com/IBM/compliance-to-policy/pkg/parser" + "github.com/oscal-compass/compliance-to-policy/go/pkg/parser" ) var TARGETS = []string{ diff --git a/cmd/parse/modules/parse.go b/go/cmd/parse/modules/parse.go similarity index 94% rename from cmd/parse/modules/parse.go rename to go/cmd/parse/modules/parse.go index 87645c5..80972c6 100644 --- a/cmd/parse/modules/parse.go +++ b/go/cmd/parse/modules/parse.go @@ -24,10 +24,10 @@ import ( "go.uber.org/zap" "gopkg.in/yaml.v3" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/parser" - "github.com/IBM/compliance-to-policy/pkg/tables/resources" - "github.com/IBM/compliance-to-policy/pkg/types/policycomposition" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/parser" + "github.com/oscal-compass/compliance-to-policy/go/pkg/tables/resources" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policycomposition" ) var TARGETS = []string{ diff --git a/cmd/parse/parse.go b/go/cmd/parse/parse.go similarity index 94% rename from cmd/parse/parse.go rename to go/cmd/parse/parse.go index f656c64..75627f0 100644 --- a/cmd/parse/parse.go +++ b/go/cmd/parse/parse.go @@ -22,7 +22,7 @@ import ( "go.uber.org/zap" - "github.com/IBM/compliance-to-policy/cmd/parse/modules" + "github.com/oscal-compass/compliance-to-policy/go/cmd/parse/modules" ) var TARGETS = []string{ diff --git a/cmd/publisher/publisher.go b/go/cmd/publisher/publisher.go similarity index 83% rename from cmd/publisher/publisher.go rename to go/cmd/publisher/publisher.go index 584998b..5571d4a 100644 --- a/cmd/publisher/publisher.go +++ b/go/cmd/publisher/publisher.go @@ -20,11 +20,11 @@ import ( "flag" "os" - compliancetopolicycontrollerv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/composer" - "github.com/IBM/compliance-to-policy/controllers/utils/gitrepo" - "github.com/IBM/compliance-to-policy/controllers/utils/publisher" - "github.com/IBM/compliance-to-policy/pkg" + compliancetopolicycontrollerv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/composer" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/gitrepo" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/publisher" + "github.com/oscal-compass/compliance-to-policy/go/pkg" ) func main() { diff --git a/cmd/publisher/samples/compliancedeployment.yaml b/go/cmd/publisher/samples/compliancedeployment.yaml similarity index 100% rename from cmd/publisher/samples/compliancedeployment.yaml rename to go/cmd/publisher/samples/compliancedeployment.yaml diff --git a/cmd/publisher/samples/component-definition.json b/go/cmd/publisher/samples/component-definition.json similarity index 100% rename from cmd/publisher/samples/component-definition.json rename to go/cmd/publisher/samples/component-definition.json diff --git a/cmd/publisher/samples/component-definition.low.json b/go/cmd/publisher/samples/component-definition.low.json similarity index 100% rename from cmd/publisher/samples/component-definition.low.json rename to go/cmd/publisher/samples/component-definition.low.json diff --git a/cmd/pvpcommon/oscal2posture/cmd/cmd.go b/go/cmd/pvpcommon/oscal2posture/cmd/cmd.go similarity index 84% rename from cmd/pvpcommon/oscal2posture/cmd/cmd.go rename to go/cmd/pvpcommon/oscal2posture/cmd/cmd.go index e154d51..402642f 100644 --- a/cmd/pvpcommon/oscal2posture/cmd/cmd.go +++ b/go/cmd/pvpcommon/oscal2posture/cmd/cmd.go @@ -23,11 +23,11 @@ import ( "github.com/spf13/cobra" "go.uber.org/zap" - "github.com/IBM/compliance-to-policy/cmd/pvpcommon/oscal2posture/options" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/kyverno" - "github.com/IBM/compliance-to-policy/pkg/pvpcommon" - typec2pcr "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" + "github.com/oscal-compass/compliance-to-policy/go/cmd/pvpcommon/oscal2posture/options" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/kyverno" + "github.com/oscal-compass/compliance-to-policy/go/pkg/pvpcommon" + typec2pcr "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" ) func New(logger *zap.Logger) *cobra.Command { diff --git a/cmd/pvpcommon/oscal2posture/options/options.go b/go/cmd/pvpcommon/oscal2posture/options/options.go similarity index 100% rename from cmd/pvpcommon/oscal2posture/options/options.go rename to go/cmd/pvpcommon/oscal2posture/options/options.go diff --git a/cmd/viewer/viewer.go b/go/cmd/viewer/viewer.go similarity index 92% rename from cmd/viewer/viewer.go rename to go/cmd/viewer/viewer.go index 5ad5e98..3d57bbb 100644 --- a/cmd/viewer/viewer.go +++ b/go/cmd/viewer/viewer.go @@ -22,9 +22,9 @@ import ( "net/url" "os" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/tables/resources" - "github.com/IBM/compliance-to-policy/pkg/types/policycomposition" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/tables/resources" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policycomposition" "gopkg.in/yaml.v3" ) diff --git a/config/crd/bases/_.yaml b/go/config/crd/bases/_.yaml similarity index 100% rename from config/crd/bases/_.yaml rename to go/config/crd/bases/_.yaml diff --git a/config/crd/bases/compliance-to-policy.io_checkpolicies.yaml b/go/config/crd/bases/compliance-to-policy.io_checkpolicies.yaml similarity index 100% rename from config/crd/bases/compliance-to-policy.io_checkpolicies.yaml rename to go/config/crd/bases/compliance-to-policy.io_checkpolicies.yaml diff --git a/config/crd/bases/compliance-to-policy.io_compliancedeployments.yaml b/go/config/crd/bases/compliance-to-policy.io_compliancedeployments.yaml similarity index 100% rename from config/crd/bases/compliance-to-policy.io_compliancedeployments.yaml rename to go/config/crd/bases/compliance-to-policy.io_compliancedeployments.yaml diff --git a/config/crd/bases/compliance-to-policy.io_compliancereports.yaml b/go/config/crd/bases/compliance-to-policy.io_compliancereports.yaml similarity index 100% rename from config/crd/bases/compliance-to-policy.io_compliancereports.yaml rename to go/config/crd/bases/compliance-to-policy.io_compliancereports.yaml diff --git a/config/crd/bases/compliance-to-policy.io_controlreferencekcps.yaml b/go/config/crd/bases/compliance-to-policy.io_controlreferencekcps.yaml similarity index 100% rename from config/crd/bases/compliance-to-policy.io_controlreferencekcps.yaml rename to go/config/crd/bases/compliance-to-policy.io_controlreferencekcps.yaml diff --git a/config/crd/bases/compliance-to-policy.io_controlreferences.yaml b/go/config/crd/bases/compliance-to-policy.io_controlreferences.yaml similarity index 100% rename from config/crd/bases/compliance-to-policy.io_controlreferences.yaml rename to go/config/crd/bases/compliance-to-policy.io_controlreferences.yaml diff --git a/config/crd/bases/compliance-to-policy.io_resultcollectors.yaml b/go/config/crd/bases/compliance-to-policy.io_resultcollectors.yaml similarity index 100% rename from config/crd/bases/compliance-to-policy.io_resultcollectors.yaml rename to go/config/crd/bases/compliance-to-policy.io_resultcollectors.yaml diff --git a/config/crd/bases/wgpolicyk8s.io_clusterpolicyreports.yaml b/go/config/crd/bases/wgpolicyk8s.io_clusterpolicyreports.yaml similarity index 100% rename from config/crd/bases/wgpolicyk8s.io_clusterpolicyreports.yaml rename to go/config/crd/bases/wgpolicyk8s.io_clusterpolicyreports.yaml diff --git a/config/crd/bases/wgpolicyk8s.io_policyreports.yaml b/go/config/crd/bases/wgpolicyk8s.io_policyreports.yaml similarity index 100% rename from config/crd/bases/wgpolicyk8s.io_policyreports.yaml rename to go/config/crd/bases/wgpolicyk8s.io_policyreports.yaml diff --git a/config/crd/kustomization.yaml b/go/config/crd/kustomization.yaml similarity index 100% rename from config/crd/kustomization.yaml rename to go/config/crd/kustomization.yaml diff --git a/config/crd/kustomizeconfig.yaml b/go/config/crd/kustomizeconfig.yaml similarity index 100% rename from config/crd/kustomizeconfig.yaml rename to go/config/crd/kustomizeconfig.yaml diff --git a/config/crd/patches/cainjection_in_compliancedeployments.yaml b/go/config/crd/patches/cainjection_in_compliancedeployments.yaml similarity index 100% rename from config/crd/patches/cainjection_in_compliancedeployments.yaml rename to go/config/crd/patches/cainjection_in_compliancedeployments.yaml diff --git a/config/crd/patches/cainjection_in_controlreferences.yaml b/go/config/crd/patches/cainjection_in_controlreferences.yaml similarity index 100% rename from config/crd/patches/cainjection_in_controlreferences.yaml rename to go/config/crd/patches/cainjection_in_controlreferences.yaml diff --git a/config/crd/patches/webhook_in_compliancedeployments.yaml b/go/config/crd/patches/webhook_in_compliancedeployments.yaml similarity index 100% rename from config/crd/patches/webhook_in_compliancedeployments.yaml rename to go/config/crd/patches/webhook_in_compliancedeployments.yaml diff --git a/config/crd/patches/webhook_in_controlreferences.yaml b/go/config/crd/patches/webhook_in_controlreferences.yaml similarity index 100% rename from config/crd/patches/webhook_in_controlreferences.yaml rename to go/config/crd/patches/webhook_in_controlreferences.yaml diff --git a/config/default/kustomization.yaml b/go/config/default/kustomization.yaml similarity index 100% rename from config/default/kustomization.yaml rename to go/config/default/kustomization.yaml diff --git a/config/default/manager_auth_proxy_patch.yaml b/go/config/default/manager_auth_proxy_patch.yaml similarity index 100% rename from config/default/manager_auth_proxy_patch.yaml rename to go/config/default/manager_auth_proxy_patch.yaml diff --git a/config/default/manager_config_patch.yaml b/go/config/default/manager_config_patch.yaml similarity index 100% rename from config/default/manager_config_patch.yaml rename to go/config/default/manager_config_patch.yaml diff --git a/config/manager/kustomization.yaml b/go/config/manager/kustomization.yaml similarity index 100% rename from config/manager/kustomization.yaml rename to go/config/manager/kustomization.yaml diff --git a/config/manager/manager.yaml b/go/config/manager/manager.yaml similarity index 100% rename from config/manager/manager.yaml rename to go/config/manager/manager.yaml diff --git a/config/manifests/kustomization.yaml b/go/config/manifests/kustomization.yaml similarity index 100% rename from config/manifests/kustomization.yaml rename to go/config/manifests/kustomization.yaml diff --git a/config/ocm/apps.open-cluster-management.io_placementrules_crd.yaml b/go/config/ocm/apps.open-cluster-management.io_placementrules_crd.yaml similarity index 100% rename from config/ocm/apps.open-cluster-management.io_placementrules_crd.yaml rename to go/config/ocm/apps.open-cluster-management.io_placementrules_crd.yaml diff --git a/config/ocm/policy.open-cluster-management.io_placementbindings.yaml b/go/config/ocm/policy.open-cluster-management.io_placementbindings.yaml similarity index 100% rename from config/ocm/policy.open-cluster-management.io_placementbindings.yaml rename to go/config/ocm/policy.open-cluster-management.io_placementbindings.yaml diff --git a/config/ocm/policy.open-cluster-management.io_policies.yaml b/go/config/ocm/policy.open-cluster-management.io_policies.yaml similarity index 100% rename from config/ocm/policy.open-cluster-management.io_policies.yaml rename to go/config/ocm/policy.open-cluster-management.io_policies.yaml diff --git a/config/ocm/policy.open-cluster-management.io_policysets.yaml b/go/config/ocm/policy.open-cluster-management.io_policysets.yaml similarity index 100% rename from config/ocm/policy.open-cluster-management.io_policysets.yaml rename to go/config/ocm/policy.open-cluster-management.io_policysets.yaml diff --git a/config/prometheus/kustomization.yaml b/go/config/prometheus/kustomization.yaml similarity index 100% rename from config/prometheus/kustomization.yaml rename to go/config/prometheus/kustomization.yaml diff --git a/config/prometheus/monitor.yaml b/go/config/prometheus/monitor.yaml similarity index 100% rename from config/prometheus/monitor.yaml rename to go/config/prometheus/monitor.yaml diff --git a/config/rbac/auth_proxy_client_clusterrole.yaml b/go/config/rbac/auth_proxy_client_clusterrole.yaml similarity index 100% rename from config/rbac/auth_proxy_client_clusterrole.yaml rename to go/config/rbac/auth_proxy_client_clusterrole.yaml diff --git a/config/rbac/auth_proxy_role.yaml b/go/config/rbac/auth_proxy_role.yaml similarity index 100% rename from config/rbac/auth_proxy_role.yaml rename to go/config/rbac/auth_proxy_role.yaml diff --git a/config/rbac/auth_proxy_role_binding.yaml b/go/config/rbac/auth_proxy_role_binding.yaml similarity index 100% rename from config/rbac/auth_proxy_role_binding.yaml rename to go/config/rbac/auth_proxy_role_binding.yaml diff --git a/config/rbac/auth_proxy_service.yaml b/go/config/rbac/auth_proxy_service.yaml similarity index 100% rename from config/rbac/auth_proxy_service.yaml rename to go/config/rbac/auth_proxy_service.yaml diff --git a/config/rbac/compliancedeployment_editor_role.yaml b/go/config/rbac/compliancedeployment_editor_role.yaml similarity index 100% rename from config/rbac/compliancedeployment_editor_role.yaml rename to go/config/rbac/compliancedeployment_editor_role.yaml diff --git a/config/rbac/compliancedeployment_viewer_role.yaml b/go/config/rbac/compliancedeployment_viewer_role.yaml similarity index 100% rename from config/rbac/compliancedeployment_viewer_role.yaml rename to go/config/rbac/compliancedeployment_viewer_role.yaml diff --git a/config/rbac/controlreference_editor_role.yaml b/go/config/rbac/controlreference_editor_role.yaml similarity index 100% rename from config/rbac/controlreference_editor_role.yaml rename to go/config/rbac/controlreference_editor_role.yaml diff --git a/config/rbac/controlreference_viewer_role.yaml b/go/config/rbac/controlreference_viewer_role.yaml similarity index 100% rename from config/rbac/controlreference_viewer_role.yaml rename to go/config/rbac/controlreference_viewer_role.yaml diff --git a/config/rbac/kustomization.yaml b/go/config/rbac/kustomization.yaml similarity index 100% rename from config/rbac/kustomization.yaml rename to go/config/rbac/kustomization.yaml diff --git a/config/rbac/leader_election_role.yaml b/go/config/rbac/leader_election_role.yaml similarity index 100% rename from config/rbac/leader_election_role.yaml rename to go/config/rbac/leader_election_role.yaml diff --git a/config/rbac/leader_election_role_binding.yaml b/go/config/rbac/leader_election_role_binding.yaml similarity index 100% rename from config/rbac/leader_election_role_binding.yaml rename to go/config/rbac/leader_election_role_binding.yaml diff --git a/config/rbac/role.yaml b/go/config/rbac/role.yaml similarity index 100% rename from config/rbac/role.yaml rename to go/config/rbac/role.yaml diff --git a/config/rbac/role_binding.yaml b/go/config/rbac/role_binding.yaml similarity index 100% rename from config/rbac/role_binding.yaml rename to go/config/rbac/role_binding.yaml diff --git a/config/rbac/service_account.yaml b/go/config/rbac/service_account.yaml similarity index 100% rename from config/rbac/service_account.yaml rename to go/config/rbac/service_account.yaml diff --git a/config/samples/compliance-to-policy_v1alpha1_compliancedeployment.kcp.yaml b/go/config/samples/compliance-to-policy_v1alpha1_compliancedeployment.kcp.yaml similarity index 100% rename from config/samples/compliance-to-policy_v1alpha1_compliancedeployment.kcp.yaml rename to go/config/samples/compliance-to-policy_v1alpha1_compliancedeployment.kcp.yaml diff --git a/config/samples/compliance-to-policy_v1alpha1_compliancedeployment.yaml b/go/config/samples/compliance-to-policy_v1alpha1_compliancedeployment.yaml similarity index 100% rename from config/samples/compliance-to-policy_v1alpha1_compliancedeployment.yaml rename to go/config/samples/compliance-to-policy_v1alpha1_compliancedeployment.yaml diff --git a/config/samples/compliance-to-policy_v1alpha1_controlreference.yaml b/go/config/samples/compliance-to-policy_v1alpha1_controlreference.yaml similarity index 100% rename from config/samples/compliance-to-policy_v1alpha1_controlreference.yaml rename to go/config/samples/compliance-to-policy_v1alpha1_controlreference.yaml diff --git a/config/samples/compliance-to-policy_v1alpha1_controlreferencekcp.yaml b/go/config/samples/compliance-to-policy_v1alpha1_controlreferencekcp.yaml similarity index 100% rename from config/samples/compliance-to-policy_v1alpha1_controlreferencekcp.yaml rename to go/config/samples/compliance-to-policy_v1alpha1_controlreferencekcp.yaml diff --git a/config/samples/kustomization.yaml b/go/config/samples/kustomization.yaml similarity index 100% rename from config/samples/kustomization.yaml rename to go/config/samples/kustomization.yaml diff --git a/config/scorecard/bases/config.yaml b/go/config/scorecard/bases/config.yaml similarity index 100% rename from config/scorecard/bases/config.yaml rename to go/config/scorecard/bases/config.yaml diff --git a/config/scorecard/kustomization.yaml b/go/config/scorecard/kustomization.yaml similarity index 100% rename from config/scorecard/kustomization.yaml rename to go/config/scorecard/kustomization.yaml diff --git a/config/scorecard/patches/basic.config.yaml b/go/config/scorecard/patches/basic.config.yaml similarity index 100% rename from config/scorecard/patches/basic.config.yaml rename to go/config/scorecard/patches/basic.config.yaml diff --git a/config/scorecard/patches/olm.config.yaml b/go/config/scorecard/patches/olm.config.yaml similarity index 100% rename from config/scorecard/patches/olm.config.yaml rename to go/config/scorecard/patches/olm.config.yaml diff --git a/config/wgpolicyk8s/v1alpha1/wgpolicyk8s.io_clusterpolicyreports.yaml b/go/config/wgpolicyk8s/v1alpha1/wgpolicyk8s.io_clusterpolicyreports.yaml similarity index 100% rename from config/wgpolicyk8s/v1alpha1/wgpolicyk8s.io_clusterpolicyreports.yaml rename to go/config/wgpolicyk8s/v1alpha1/wgpolicyk8s.io_clusterpolicyreports.yaml diff --git a/config/wgpolicyk8s/v1alpha1/wgpolicyk8s.io_policyreports.yaml b/go/config/wgpolicyk8s/v1alpha1/wgpolicyk8s.io_policyreports.yaml similarity index 100% rename from config/wgpolicyk8s/v1alpha1/wgpolicyk8s.io_policyreports.yaml rename to go/config/wgpolicyk8s/v1alpha1/wgpolicyk8s.io_policyreports.yaml diff --git a/config/wgpolicyk8s/v1alpha2/wgpolicyk8s.io_clusterpolicyreports.yaml b/go/config/wgpolicyk8s/v1alpha2/wgpolicyk8s.io_clusterpolicyreports.yaml similarity index 100% rename from config/wgpolicyk8s/v1alpha2/wgpolicyk8s.io_clusterpolicyreports.yaml rename to go/config/wgpolicyk8s/v1alpha2/wgpolicyk8s.io_clusterpolicyreports.yaml diff --git a/config/wgpolicyk8s/v1alpha2/wgpolicyk8s.io_policyreports.yaml b/go/config/wgpolicyk8s/v1alpha2/wgpolicyk8s.io_policyreports.yaml similarity index 100% rename from config/wgpolicyk8s/v1alpha2/wgpolicyk8s.io_policyreports.yaml rename to go/config/wgpolicyk8s/v1alpha2/wgpolicyk8s.io_policyreports.yaml diff --git a/config/wgpolicyk8s/v1beta1/wgpolicyk8s.io_clusterpolicyreports.yaml b/go/config/wgpolicyk8s/v1beta1/wgpolicyk8s.io_clusterpolicyreports.yaml similarity index 100% rename from config/wgpolicyk8s/v1beta1/wgpolicyk8s.io_clusterpolicyreports.yaml rename to go/config/wgpolicyk8s/v1beta1/wgpolicyk8s.io_clusterpolicyreports.yaml diff --git a/config/wgpolicyk8s/v1beta1/wgpolicyk8s.io_policyreports.yaml b/go/config/wgpolicyk8s/v1beta1/wgpolicyk8s.io_policyreports.yaml similarity index 100% rename from config/wgpolicyk8s/v1beta1/wgpolicyk8s.io_policyreports.yaml rename to go/config/wgpolicyk8s/v1beta1/wgpolicyk8s.io_policyreports.yaml diff --git a/controllers/compliancedeployment/controller.go b/go/controllers/compliancedeployment/controller.go similarity index 96% rename from controllers/compliancedeployment/controller.go rename to go/controllers/compliancedeployment/controller.go index 26dd8e4..225feb6 100644 --- a/controllers/compliancedeployment/controller.go +++ b/go/controllers/compliancedeployment/controller.go @@ -29,8 +29,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - c2pv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/utils" + c2pv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils" ) // ComplianceDeploymentReconciler reconciles a ComplianceDeployment object diff --git a/controllers/compliancedeployment/controller_test.go b/go/controllers/compliancedeployment/controller_test.go similarity index 93% rename from controllers/compliancedeployment/controller_test.go rename to go/controllers/compliancedeployment/controller_test.go index aeabce0..e3a6afe 100644 --- a/controllers/compliancedeployment/controller_test.go +++ b/go/controllers/compliancedeployment/controller_test.go @@ -23,11 +23,11 @@ import ( "testing" "time" - ctrlv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/utils/ocmk8sclients" - "github.com/IBM/compliance-to-policy/pkg" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + ctrlv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/ocmk8sclients" + "github.com/oscal-compass/compliance-to-policy/go/pkg" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -37,8 +37,8 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - ctrlrefocm "github.com/IBM/compliance-to-policy/controllers/controlreference/ocm" - "github.com/IBM/compliance-to-policy/controllers/testsetting" + ctrlrefocm "github.com/oscal-compass/compliance-to-policy/go/controllers/controlreference/ocm" + "github.com/oscal-compass/compliance-to-policy/go/controllers/testsetting" ) var testSetting *testsetting.TestSetting diff --git a/controllers/composer/composer.go b/go/controllers/composer/composer.go similarity index 96% rename from controllers/composer/composer.go rename to go/controllers/composer/composer.go index 5fbe1fd..6cb1e7d 100644 --- a/controllers/composer/composer.go +++ b/go/controllers/composer/composer.go @@ -21,13 +21,13 @@ import ( "os" "strings" - policygenerator "github.com/IBM/compliance-to-policy/pkg/policygenerator" - . "github.com/IBM/compliance-to-policy/pkg/types/internalcompliance" - pgtype "github.com/IBM/compliance-to-policy/pkg/types/policygenerator" + policygenerator "github.com/oscal-compass/compliance-to-policy/go/pkg/policygenerator" + . "github.com/oscal-compass/compliance-to-policy/go/pkg/types/internalcompliance" + pgtype "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policygenerator" cp "github.com/otiai10/copy" typekustomize "sigs.k8s.io/kustomize/api/types" - "github.com/IBM/compliance-to-policy/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg" "go.uber.org/zap" "k8s.io/apimachinery/pkg/util/sets" ) diff --git a/controllers/composer/composer_test.go b/go/controllers/composer/composer_test.go similarity index 94% rename from controllers/composer/composer_test.go rename to go/controllers/composer/composer_test.go index 306224e..47bae19 100644 --- a/controllers/composer/composer_test.go +++ b/go/controllers/composer/composer_test.go @@ -21,11 +21,11 @@ import ( "os" "testing" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/types/configurationpolicy" - . "github.com/IBM/compliance-to-policy/pkg/types/internalcompliance" - "github.com/IBM/compliance-to-policy/pkg/types/placements" - typepolicy "github.com/IBM/compliance-to-policy/pkg/types/policy" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/configurationpolicy" + . "github.com/oscal-compass/compliance-to-policy/go/pkg/types/internalcompliance" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/placements" + typepolicy "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policy" "github.com/stretchr/testify/assert" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" diff --git a/controllers/composer/helper.go b/go/controllers/composer/helper.go similarity index 94% rename from controllers/composer/helper.go rename to go/controllers/composer/helper.go index 607e937..ceb1c07 100644 --- a/controllers/composer/helper.go +++ b/go/controllers/composer/helper.go @@ -22,11 +22,11 @@ import ( "sort" "strings" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/types/configurationpolicy" - . "github.com/IBM/compliance-to-policy/pkg/types/internalcompliance" - typespolicy "github.com/IBM/compliance-to-policy/pkg/types/policy" - pgtype "github.com/IBM/compliance-to-policy/pkg/types/policygenerator" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/configurationpolicy" + . "github.com/oscal-compass/compliance-to-policy/go/pkg/types/internalcompliance" + typespolicy "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policy" + pgtype "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policygenerator" cp "github.com/otiai10/copy" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" utilyaml "k8s.io/apimachinery/pkg/util/yaml" diff --git a/controllers/composer/testdata/compliance.yaml b/go/controllers/composer/testdata/compliance.yaml similarity index 100% rename from controllers/composer/testdata/compliance.yaml rename to go/controllers/composer/testdata/compliance.yaml diff --git a/controllers/composer/testdata/expected/c2pcr-parser-composed-policies/add-chrony.yaml b/go/controllers/composer/testdata/expected/c2pcr-parser-composed-policies/add-chrony.yaml similarity index 100% rename from controllers/composer/testdata/expected/c2pcr-parser-composed-policies/add-chrony.yaml rename to go/controllers/composer/testdata/expected/c2pcr-parser-composed-policies/add-chrony.yaml diff --git a/controllers/composer/testdata/expected/c2pcr-parser-composed-policies/install-odf-lvm-operator.yaml b/go/controllers/composer/testdata/expected/c2pcr-parser-composed-policies/install-odf-lvm-operator.yaml similarity index 100% rename from controllers/composer/testdata/expected/c2pcr-parser-composed-policies/install-odf-lvm-operator.yaml rename to go/controllers/composer/testdata/expected/c2pcr-parser-composed-policies/install-odf-lvm-operator.yaml diff --git a/controllers/composer/testdata/expected/c2pcr-parser-composed-policies/policy-nginx-deployment.yaml b/go/controllers/composer/testdata/expected/c2pcr-parser-composed-policies/policy-nginx-deployment.yaml similarity index 100% rename from controllers/composer/testdata/expected/c2pcr-parser-composed-policies/policy-nginx-deployment.yaml rename to go/controllers/composer/testdata/expected/c2pcr-parser-composed-policies/policy-nginx-deployment.yaml diff --git a/controllers/composer/testdata/expected/composed-config-policies/add-chrony/add-chrony.yaml b/go/controllers/composer/testdata/expected/composed-config-policies/add-chrony/add-chrony.yaml similarity index 100% rename from controllers/composer/testdata/expected/composed-config-policies/add-chrony/add-chrony.yaml rename to go/controllers/composer/testdata/expected/composed-config-policies/add-chrony/add-chrony.yaml diff --git a/controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator.yaml b/go/controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator.yaml similarity index 100% rename from controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator.yaml rename to go/controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator.yaml diff --git a/controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator2.yaml b/go/controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator2.yaml similarity index 100% rename from controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator2.yaml rename to go/controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator2.yaml diff --git a/controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator3.yaml b/go/controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator3.yaml similarity index 100% rename from controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator3.yaml rename to go/controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator3.yaml diff --git a/controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator4.yaml b/go/controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator4.yaml similarity index 100% rename from controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator4.yaml rename to go/controllers/composer/testdata/expected/composed-config-policies/install-odf-lvm-operator/install-odf-lvm-operator4.yaml diff --git a/controllers/composer/testdata/expected/composed-policies/add-chrony.yaml b/go/controllers/composer/testdata/expected/composed-policies/add-chrony.yaml similarity index 100% rename from controllers/composer/testdata/expected/composed-policies/add-chrony.yaml rename to go/controllers/composer/testdata/expected/composed-policies/add-chrony.yaml diff --git a/controllers/composer/testdata/expected/composed-policies/install-odf-lvm-operator.yaml b/go/controllers/composer/testdata/expected/composed-policies/install-odf-lvm-operator.yaml similarity index 100% rename from controllers/composer/testdata/expected/composed-policies/install-odf-lvm-operator.yaml rename to go/controllers/composer/testdata/expected/composed-policies/install-odf-lvm-operator.yaml diff --git a/controllers/composer/testdata/oscal/catalog.json b/go/controllers/composer/testdata/oscal/catalog.json similarity index 100% rename from controllers/composer/testdata/oscal/catalog.json rename to go/controllers/composer/testdata/oscal/catalog.json diff --git a/controllers/composer/testdata/oscal/component-definition.json b/go/controllers/composer/testdata/oscal/component-definition.json similarity index 100% rename from controllers/composer/testdata/oscal/component-definition.json rename to go/controllers/composer/testdata/oscal/component-definition.json diff --git a/controllers/composer/testdata/oscal/profile.json b/go/controllers/composer/testdata/oscal/profile.json similarity index 100% rename from controllers/composer/testdata/oscal/profile.json rename to go/controllers/composer/testdata/oscal/profile.json diff --git a/controllers/composer/testdata/policies/add-chrony/add-chrony-worker/MachineConfig.50-worker-chrony.0.yaml b/go/controllers/composer/testdata/policies/add-chrony/add-chrony-worker/MachineConfig.50-worker-chrony.0.yaml similarity index 100% rename from controllers/composer/testdata/policies/add-chrony/add-chrony-worker/MachineConfig.50-worker-chrony.0.yaml rename to go/controllers/composer/testdata/policies/add-chrony/add-chrony-worker/MachineConfig.50-worker-chrony.0.yaml diff --git a/controllers/composer/testdata/policies/add-chrony/kustomization.yaml b/go/controllers/composer/testdata/policies/add-chrony/kustomization.yaml similarity index 100% rename from controllers/composer/testdata/policies/add-chrony/kustomization.yaml rename to go/controllers/composer/testdata/policies/add-chrony/kustomization.yaml diff --git a/controllers/composer/testdata/policies/add-chrony/policy-generator.yaml b/go/controllers/composer/testdata/policies/add-chrony/policy-generator.yaml similarity index 100% rename from controllers/composer/testdata/policies/add-chrony/policy-generator.yaml rename to go/controllers/composer/testdata/policies/add-chrony/policy-generator.yaml diff --git a/controllers/composer/testdata/policies/install-odf-lvm-operator/kustomization.yaml b/go/controllers/composer/testdata/policies/install-odf-lvm-operator/kustomization.yaml similarity index 100% rename from controllers/composer/testdata/policies/install-odf-lvm-operator/kustomization.yaml rename to go/controllers/composer/testdata/policies/install-odf-lvm-operator/kustomization.yaml diff --git a/controllers/composer/testdata/policies/install-odf-lvm-operator/odf-lvmcluster/LVMCluster.odf-lvmcluster.0.yaml b/go/controllers/composer/testdata/policies/install-odf-lvm-operator/odf-lvmcluster/LVMCluster.odf-lvmcluster.0.yaml similarity index 100% rename from controllers/composer/testdata/policies/install-odf-lvm-operator/odf-lvmcluster/LVMCluster.odf-lvmcluster.0.yaml rename to go/controllers/composer/testdata/policies/install-odf-lvm-operator/odf-lvmcluster/LVMCluster.odf-lvmcluster.0.yaml diff --git a/controllers/composer/testdata/policies/install-odf-lvm-operator/policy-generator.yaml b/go/controllers/composer/testdata/policies/install-odf-lvm-operator/policy-generator.yaml similarity index 100% rename from controllers/composer/testdata/policies/install-odf-lvm-operator/policy-generator.yaml rename to go/controllers/composer/testdata/policies/install-odf-lvm-operator/policy-generator.yaml diff --git a/controllers/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Namespace.openshift-storage.0.yaml b/go/controllers/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Namespace.openshift-storage.0.yaml similarity index 100% rename from controllers/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Namespace.openshift-storage.0.yaml rename to go/controllers/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Namespace.openshift-storage.0.yaml diff --git a/controllers/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/OperatorGroup.openshift-storage-operatorgroup.0.yaml b/go/controllers/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/OperatorGroup.openshift-storage-operatorgroup.0.yaml similarity index 100% rename from controllers/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/OperatorGroup.openshift-storage-operatorgroup.0.yaml rename to go/controllers/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/OperatorGroup.openshift-storage-operatorgroup.0.yaml diff --git a/controllers/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Subscription.lvm-operator.0.yaml b/go/controllers/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Subscription.lvm-operator.0.yaml similarity index 100% rename from controllers/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Subscription.lvm-operator.0.yaml rename to go/controllers/composer/testdata/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Subscription.lvm-operator.0.yaml diff --git a/controllers/composer/testdata/policies/policy-nginx-deployment/kustomization.yaml b/go/controllers/composer/testdata/policies/policy-nginx-deployment/kustomization.yaml similarity index 100% rename from controllers/composer/testdata/policies/policy-nginx-deployment/kustomization.yaml rename to go/controllers/composer/testdata/policies/policy-nginx-deployment/kustomization.yaml diff --git a/controllers/composer/testdata/policies/policy-nginx-deployment/policy-generator.yaml b/go/controllers/composer/testdata/policies/policy-nginx-deployment/policy-generator.yaml similarity index 100% rename from controllers/composer/testdata/policies/policy-nginx-deployment/policy-generator.yaml rename to go/controllers/composer/testdata/policies/policy-nginx-deployment/policy-generator.yaml diff --git a/controllers/composer/testdata/policies/policy-nginx-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml b/go/controllers/composer/testdata/policies/policy-nginx-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml similarity index 100% rename from controllers/composer/testdata/policies/policy-nginx-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml rename to go/controllers/composer/testdata/policies/policy-nginx-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml diff --git a/controllers/controlreference/kcp/controller.go b/go/controllers/controlreference/kcp/controller.go similarity index 96% rename from controllers/controlreference/kcp/controller.go rename to go/controllers/controlreference/kcp/controller.go index c4b4234..77ebeda 100644 --- a/controllers/controlreference/kcp/controller.go +++ b/go/controllers/controlreference/kcp/controller.go @@ -32,13 +32,13 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - c2pv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/composer" - "github.com/IBM/compliance-to-policy/controllers/utils" - "github.com/IBM/compliance-to-policy/controllers/utils/kcpclient" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/types/internalcompliance" "github.com/go-logr/logr" + c2pv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/composer" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/kcpclient" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/internalcompliance" ) var logger logr.Logger = ctrl.Log.WithName("control-reference-controller-kcp") diff --git a/controllers/controlreference/kcp/controller_test.go b/go/controllers/controlreference/kcp/controller_test.go similarity index 95% rename from controllers/controlreference/kcp/controller_test.go rename to go/controllers/controlreference/kcp/controller_test.go index 5110026..df7c1fa 100644 --- a/controllers/controlreference/kcp/controller_test.go +++ b/go/controllers/controlreference/kcp/controller_test.go @@ -22,12 +22,12 @@ import ( "testing" "time" - ctrlv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/testsetting" - "github.com/IBM/compliance-to-policy/controllers/utils/kcpclient" - "github.com/IBM/compliance-to-policy/pkg" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + ctrlv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/testsetting" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/kcpclient" + "github.com/oscal-compass/compliance-to-policy/go/pkg" apixv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apix "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/controllers/controlreference/kcp/helper.go b/go/controllers/controlreference/kcp/helper.go similarity index 97% rename from controllers/controlreference/kcp/helper.go rename to go/controllers/controlreference/kcp/helper.go index d35d367..88e25c8 100644 --- a/controllers/controlreference/kcp/helper.go +++ b/go/controllers/controlreference/kcp/helper.go @@ -6,12 +6,12 @@ import ( "strings" "time" - c2pv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - edgev1alpha1 "github.com/IBM/compliance-to-policy/controllers/edge.kcp.io/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/utils/kcpclient" - "github.com/IBM/compliance-to-policy/pkg" kcpv1alpha1 "github.com/kcp-dev/kcp/pkg/apis/apis/v1alpha1" tenancyv1alpha1 "github.com/kcp-dev/kcp/pkg/apis/tenancy/v1alpha1" + c2pv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + edgev1alpha1 "github.com/oscal-compass/compliance-to-policy/go/controllers/edge.kcp.io/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/kcpclient" + "github.com/oscal-compass/compliance-to-policy/go/pkg" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/controllers/controlreference/ocm/controller.go b/go/controllers/controlreference/ocm/controller.go similarity index 93% rename from controllers/controlreference/ocm/controller.go rename to go/controllers/controlreference/ocm/controller.go index fa8c4e4..8e3942a 100644 --- a/controllers/controlreference/ocm/controller.go +++ b/go/controllers/controlreference/ocm/controller.go @@ -28,14 +28,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - compliancetopolicycontrollerv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/composer" - "github.com/IBM/compliance-to-policy/controllers/utils" - "github.com/IBM/compliance-to-policy/controllers/utils/ocmk8sclients" - "github.com/IBM/compliance-to-policy/pkg/types/internalcompliance" - typesplacement "github.com/IBM/compliance-to-policy/pkg/types/placements" - typespolicy "github.com/IBM/compliance-to-policy/pkg/types/policy" "github.com/go-logr/logr" + compliancetopolicycontrollerv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/composer" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/ocmk8sclients" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/internalcompliance" + typesplacement "github.com/oscal-compass/compliance-to-policy/go/pkg/types/placements" + typespolicy "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policy" utilyaml "k8s.io/apimachinery/pkg/util/yaml" ) diff --git a/controllers/controlreference/ocm/controller_test.go b/go/controllers/controlreference/ocm/controller_test.go similarity index 93% rename from controllers/controlreference/ocm/controller_test.go rename to go/controllers/controlreference/ocm/controller_test.go index 6b44a42..7625560 100644 --- a/controllers/controlreference/ocm/controller_test.go +++ b/go/controllers/controlreference/ocm/controller_test.go @@ -19,11 +19,11 @@ package ocm import ( "context" - ctrlv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/utils/ocmk8sclients" - "github.com/IBM/compliance-to-policy/pkg" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + ctrlv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/ocmk8sclients" + "github.com/oscal-compass/compliance-to-policy/go/pkg" "sigs.k8s.io/controller-runtime/pkg/client" "os" @@ -36,7 +36,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - "github.com/IBM/compliance-to-policy/controllers/testsetting" + "github.com/oscal-compass/compliance-to-policy/go/controllers/testsetting" ) var testSetting *testsetting.TestSetting diff --git a/controllers/edge.kcp.io/v1alpha1/customize.go b/go/controllers/edge.kcp.io/v1alpha1/customize.go similarity index 100% rename from controllers/edge.kcp.io/v1alpha1/customize.go rename to go/controllers/edge.kcp.io/v1alpha1/customize.go diff --git a/controllers/edge.kcp.io/v1alpha1/edge-placement.go b/go/controllers/edge.kcp.io/v1alpha1/edge-placement.go similarity index 100% rename from controllers/edge.kcp.io/v1alpha1/edge-placement.go rename to go/controllers/edge.kcp.io/v1alpha1/edge-placement.go diff --git a/controllers/edge.kcp.io/v1alpha1/single-placement.go b/go/controllers/edge.kcp.io/v1alpha1/single-placement.go similarity index 100% rename from controllers/edge.kcp.io/v1alpha1/single-placement.go rename to go/controllers/edge.kcp.io/v1alpha1/single-placement.go diff --git a/controllers/resultcollector/collector.go b/go/controllers/resultcollector/collector.go similarity index 97% rename from controllers/resultcollector/collector.go rename to go/controllers/resultcollector/collector.go index 7fe0b81..60db3a4 100644 --- a/controllers/resultcollector/collector.go +++ b/go/controllers/resultcollector/collector.go @@ -21,10 +21,10 @@ import ( "fmt" "strings" - c2pv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/utils" - "github.com/IBM/compliance-to-policy/controllers/utils/kcpclient" - wgpolicyk8sv1alpha2 "github.com/IBM/compliance-to-policy/controllers/wgpolicyk8s.io/v1alpha2" + c2pv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/kcpclient" + wgpolicyk8sv1alpha2 "github.com/oscal-compass/compliance-to-policy/go/controllers/wgpolicyk8s.io/v1alpha2" corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/rest" diff --git a/controllers/resultcollector/controller.go b/go/controllers/resultcollector/controller.go similarity index 96% rename from controllers/resultcollector/controller.go rename to go/controllers/resultcollector/controller.go index 6911748..5104922 100644 --- a/controllers/resultcollector/controller.go +++ b/go/controllers/resultcollector/controller.go @@ -22,9 +22,9 @@ import ( "sync" "time" - c2pv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/utils" "github.com/go-logr/logr" + c2pv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/rest" diff --git a/controllers/resultcollector/validator.go b/go/controllers/resultcollector/validator.go similarity index 97% rename from controllers/resultcollector/validator.go rename to go/controllers/resultcollector/validator.go index 5178342..4de2c4e 100644 --- a/controllers/resultcollector/validator.go +++ b/go/controllers/resultcollector/validator.go @@ -21,9 +21,9 @@ import ( "fmt" "strings" - c2pv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/utils/kcpclient" - "github.com/IBM/compliance-to-policy/pkg" + c2pv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/kcpclient" + "github.com/oscal-compass/compliance-to-policy/go/pkg" "k8s.io/apimachinery/pkg/api/errors" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" diff --git a/controllers/testdata/compliancedeployment.yaml b/go/controllers/testdata/compliancedeployment.yaml similarity index 100% rename from controllers/testdata/compliancedeployment.yaml rename to go/controllers/testdata/compliancedeployment.yaml diff --git a/controllers/testdata/configmap.component-definition.yaml b/go/controllers/testdata/configmap.component-definition.yaml similarity index 100% rename from controllers/testdata/configmap.component-definition.yaml rename to go/controllers/testdata/configmap.component-definition.yaml diff --git a/controllers/testdata/controlreference.yaml b/go/controllers/testdata/controlreference.yaml similarity index 100% rename from controllers/testdata/controlreference.yaml rename to go/controllers/testdata/controlreference.yaml diff --git a/controllers/testdata/controlreferencekcp.yaml b/go/controllers/testdata/controlreferencekcp.yaml similarity index 100% rename from controllers/testdata/controlreferencekcp.yaml rename to go/controllers/testdata/controlreferencekcp.yaml diff --git a/controllers/testdata/ws.test1.yaml b/go/controllers/testdata/ws.test1.yaml similarity index 100% rename from controllers/testdata/ws.test1.yaml rename to go/controllers/testdata/ws.test1.yaml diff --git a/controllers/testdata/ws.test2.yaml b/go/controllers/testdata/ws.test2.yaml similarity index 100% rename from controllers/testdata/ws.test2.yaml rename to go/controllers/testdata/ws.test2.yaml diff --git a/controllers/testsetting/common.go b/go/controllers/testsetting/common.go similarity index 100% rename from controllers/testsetting/common.go rename to go/controllers/testsetting/common.go diff --git a/controllers/testsetting/kcptestsetting.go b/go/controllers/testsetting/kcptestsetting.go similarity index 95% rename from controllers/testsetting/kcptestsetting.go rename to go/controllers/testsetting/kcptestsetting.go index ab33079..60dcba3 100644 --- a/controllers/testsetting/kcptestsetting.go +++ b/go/controllers/testsetting/kcptestsetting.go @@ -26,8 +26,8 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - compliancetopolicycontrollerv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/utils/ocmk8sclients" + compliancetopolicycontrollerv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/ocmk8sclients" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" diff --git a/controllers/testsetting/testsetting.go b/go/controllers/testsetting/testsetting.go similarity index 94% rename from controllers/testsetting/testsetting.go rename to go/controllers/testsetting/testsetting.go index 189b084..d4ba1ec 100644 --- a/controllers/testsetting/testsetting.go +++ b/go/controllers/testsetting/testsetting.go @@ -24,9 +24,9 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - compliancetopolicycontrollerv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/utils/ocmk8sclients" - "github.com/IBM/compliance-to-policy/pkg" + compliancetopolicycontrollerv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/ocmk8sclients" + "github.com/oscal-compass/compliance-to-policy/go/pkg" corev1 "k8s.io/api/core/v1" apixv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" diff --git a/controllers/utils/gitrepo/gitrepo.go b/go/controllers/utils/gitrepo/gitrepo.go similarity index 100% rename from controllers/utils/gitrepo/gitrepo.go rename to go/controllers/utils/gitrepo/gitrepo.go diff --git a/controllers/utils/gitrepo/gitrepo_test.go b/go/controllers/utils/gitrepo/gitrepo_test.go similarity index 96% rename from controllers/utils/gitrepo/gitrepo_test.go rename to go/controllers/utils/gitrepo/gitrepo_test.go index 4dc15b5..f175551 100644 --- a/controllers/utils/gitrepo/gitrepo_test.go +++ b/go/controllers/utils/gitrepo/gitrepo_test.go @@ -20,7 +20,7 @@ import ( "os" "testing" - "github.com/IBM/compliance-to-policy/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg" ) func TestGitRepo(t *testing.T) { diff --git a/controllers/utils/kcpclient/kcpclient.go b/go/controllers/utils/kcpclient/kcpclient.go similarity index 100% rename from controllers/utils/kcpclient/kcpclient.go rename to go/controllers/utils/kcpclient/kcpclient.go diff --git a/controllers/utils/kcpclient/kcpclient_test.go b/go/controllers/utils/kcpclient/kcpclient_test.go similarity index 96% rename from controllers/utils/kcpclient/kcpclient_test.go rename to go/controllers/utils/kcpclient/kcpclient_test.go index 3c64b27..31c4406 100644 --- a/controllers/utils/kcpclient/kcpclient_test.go +++ b/go/controllers/utils/kcpclient/kcpclient_test.go @@ -22,10 +22,10 @@ import ( "testing" "time" - "github.com/IBM/compliance-to-policy/controllers/testsetting" - "github.com/IBM/compliance-to-policy/pkg" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/oscal-compass/compliance-to-policy/go/controllers/testsetting" + "github.com/oscal-compass/compliance-to-policy/go/pkg" corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" diff --git a/controllers/utils/kcpclient/testdata/ws.test1.yaml b/go/controllers/utils/kcpclient/testdata/ws.test1.yaml similarity index 100% rename from controllers/utils/kcpclient/testdata/ws.test1.yaml rename to go/controllers/utils/kcpclient/testdata/ws.test1.yaml diff --git a/controllers/utils/kcpclient/testdata/ws.test2.yaml b/go/controllers/utils/kcpclient/testdata/ws.test2.yaml similarity index 100% rename from controllers/utils/kcpclient/testdata/ws.test2.yaml rename to go/controllers/utils/kcpclient/testdata/ws.test2.yaml diff --git a/controllers/utils/ocmk8sclients/ocmk8sclient.go b/go/controllers/utils/ocmk8sclients/ocmk8sclient.go similarity index 100% rename from controllers/utils/ocmk8sclients/ocmk8sclient.go rename to go/controllers/utils/ocmk8sclients/ocmk8sclient.go diff --git a/controllers/utils/ocmk8sclients/placementbindingclient.go b/go/controllers/utils/ocmk8sclients/placementbindingclient.go similarity index 94% rename from controllers/utils/ocmk8sclients/placementbindingclient.go rename to go/controllers/utils/ocmk8sclients/placementbindingclient.go index fc04b97..163cee0 100644 --- a/controllers/utils/ocmk8sclients/placementbindingclient.go +++ b/go/controllers/utils/ocmk8sclients/placementbindingclient.go @@ -19,8 +19,8 @@ package ocmk8sclients import ( "context" - "github.com/IBM/compliance-to-policy/pkg" - typesplacement "github.com/IBM/compliance-to-policy/pkg/types/placements" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + typesplacement "github.com/oscal-compass/compliance-to-policy/go/pkg/types/placements" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/dynamic" ) diff --git a/controllers/utils/ocmk8sclients/placementbindingclient_test.go b/go/controllers/utils/ocmk8sclients/placementbindingclient_test.go similarity index 93% rename from controllers/utils/ocmk8sclients/placementbindingclient_test.go rename to go/controllers/utils/ocmk8sclients/placementbindingclient_test.go index 30abc88..98c391e 100644 --- a/controllers/utils/ocmk8sclients/placementbindingclient_test.go +++ b/go/controllers/utils/ocmk8sclients/placementbindingclient_test.go @@ -17,8 +17,8 @@ limitations under the License. package ocmk8sclients import ( - "github.com/IBM/compliance-to-policy/pkg" - typesplacement "github.com/IBM/compliance-to-policy/pkg/types/placements" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + typesplacement "github.com/oscal-compass/compliance-to-policy/go/pkg/types/placements" "k8s.io/client-go/dynamic" . "github.com/onsi/ginkgo/v2" diff --git a/controllers/utils/ocmk8sclients/placementruleclient.go b/go/controllers/utils/ocmk8sclients/placementruleclient.go similarity index 94% rename from controllers/utils/ocmk8sclients/placementruleclient.go rename to go/controllers/utils/ocmk8sclients/placementruleclient.go index a05f4cf..db90164 100644 --- a/controllers/utils/ocmk8sclients/placementruleclient.go +++ b/go/controllers/utils/ocmk8sclients/placementruleclient.go @@ -19,8 +19,8 @@ package ocmk8sclients import ( "context" - "github.com/IBM/compliance-to-policy/pkg" - typesplacement "github.com/IBM/compliance-to-policy/pkg/types/placements" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + typesplacement "github.com/oscal-compass/compliance-to-policy/go/pkg/types/placements" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/dynamic" ) diff --git a/controllers/utils/ocmk8sclients/placementruleclient_test.go b/go/controllers/utils/ocmk8sclients/placementruleclient_test.go similarity index 93% rename from controllers/utils/ocmk8sclients/placementruleclient_test.go rename to go/controllers/utils/ocmk8sclients/placementruleclient_test.go index fe7c4d7..cb8d810 100644 --- a/controllers/utils/ocmk8sclients/placementruleclient_test.go +++ b/go/controllers/utils/ocmk8sclients/placementruleclient_test.go @@ -17,8 +17,8 @@ limitations under the License. package ocmk8sclients import ( - "github.com/IBM/compliance-to-policy/pkg" - typesplacement "github.com/IBM/compliance-to-policy/pkg/types/placements" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + typesplacement "github.com/oscal-compass/compliance-to-policy/go/pkg/types/placements" "k8s.io/client-go/dynamic" . "github.com/onsi/ginkgo/v2" diff --git a/controllers/utils/ocmk8sclients/policyclient.go b/go/controllers/utils/ocmk8sclients/policyclient.go similarity index 94% rename from controllers/utils/ocmk8sclients/policyclient.go rename to go/controllers/utils/ocmk8sclients/policyclient.go index 0ed0b8d..e439ea7 100644 --- a/controllers/utils/ocmk8sclients/policyclient.go +++ b/go/controllers/utils/ocmk8sclients/policyclient.go @@ -19,8 +19,8 @@ package ocmk8sclients import ( "context" - "github.com/IBM/compliance-to-policy/pkg" - typespolicy "github.com/IBM/compliance-to-policy/pkg/types/policy" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + typespolicy "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policy" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/dynamic" ) diff --git a/controllers/utils/ocmk8sclients/policyclient_test.go b/go/controllers/utils/ocmk8sclients/policyclient_test.go similarity index 93% rename from controllers/utils/ocmk8sclients/policyclient_test.go rename to go/controllers/utils/ocmk8sclients/policyclient_test.go index 80a2f70..5cd9d67 100644 --- a/controllers/utils/ocmk8sclients/policyclient_test.go +++ b/go/controllers/utils/ocmk8sclients/policyclient_test.go @@ -17,8 +17,8 @@ limitations under the License. package ocmk8sclients import ( - "github.com/IBM/compliance-to-policy/pkg" - typespolicy "github.com/IBM/compliance-to-policy/pkg/types/policy" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + typespolicy "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policy" "k8s.io/client-go/dynamic" . "github.com/onsi/ginkgo/v2" diff --git a/controllers/utils/ocmk8sclients/suite_test.go b/go/controllers/utils/ocmk8sclients/suite_test.go similarity index 96% rename from controllers/utils/ocmk8sclients/suite_test.go rename to go/controllers/utils/ocmk8sclients/suite_test.go index 65eb62d..9547939 100644 --- a/controllers/utils/ocmk8sclients/suite_test.go +++ b/go/controllers/utils/ocmk8sclients/suite_test.go @@ -38,8 +38,8 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - compliancetopolicycontrollerv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/pkg" + compliancetopolicycontrollerv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/pkg" //+kubebuilder:scaffold:imports ) diff --git a/controllers/utils/ocmk8sclients/testdata/placement-binding.sample.yaml b/go/controllers/utils/ocmk8sclients/testdata/placement-binding.sample.yaml similarity index 100% rename from controllers/utils/ocmk8sclients/testdata/placement-binding.sample.yaml rename to go/controllers/utils/ocmk8sclients/testdata/placement-binding.sample.yaml diff --git a/controllers/utils/ocmk8sclients/testdata/placement-rule.sample.yaml b/go/controllers/utils/ocmk8sclients/testdata/placement-rule.sample.yaml similarity index 100% rename from controllers/utils/ocmk8sclients/testdata/placement-rule.sample.yaml rename to go/controllers/utils/ocmk8sclients/testdata/placement-rule.sample.yaml diff --git a/controllers/utils/ocmk8sclients/testdata/policy.sample.yaml b/go/controllers/utils/ocmk8sclients/testdata/policy.sample.yaml similarity index 100% rename from controllers/utils/ocmk8sclients/testdata/policy.sample.yaml rename to go/controllers/utils/ocmk8sclients/testdata/policy.sample.yaml diff --git a/controllers/utils/publisher/publisher.go b/go/controllers/utils/publisher/publisher.go similarity index 89% rename from controllers/utils/publisher/publisher.go rename to go/controllers/utils/publisher/publisher.go index 2bb2fb0..3a391d2 100644 --- a/controllers/utils/publisher/publisher.go +++ b/go/controllers/utils/publisher/publisher.go @@ -20,12 +20,12 @@ import ( "fmt" "os" - compliancetopolicycontrollerv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/composer" - "github.com/IBM/compliance-to-policy/controllers/utils" - "github.com/IBM/compliance-to-policy/controllers/utils/gitrepo" - "github.com/IBM/compliance-to-policy/pkg" "github.com/go-logr/logr" + compliancetopolicycontrollerv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/composer" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/gitrepo" + "github.com/oscal-compass/compliance-to-policy/go/pkg" cp "github.com/otiai10/copy" ctrl "sigs.k8s.io/controller-runtime" ) diff --git a/controllers/utils/publisher/testdata/compliancedeployment.yaml b/go/controllers/utils/publisher/testdata/compliancedeployment.yaml similarity index 100% rename from controllers/utils/publisher/testdata/compliancedeployment.yaml rename to go/controllers/utils/publisher/testdata/compliancedeployment.yaml diff --git a/controllers/utils/publisher/testdata/component-definition.json b/go/controllers/utils/publisher/testdata/component-definition.json similarity index 100% rename from controllers/utils/publisher/testdata/component-definition.json rename to go/controllers/utils/publisher/testdata/component-definition.json diff --git a/controllers/utils/utils.go b/go/controllers/utils/utils.go similarity index 95% rename from controllers/utils/utils.go rename to go/controllers/utils/utils.go index 945683e..525644b 100644 --- a/controllers/utils/utils.go +++ b/go/controllers/utils/utils.go @@ -27,15 +27,15 @@ import ( "strconv" "strings" - c2pv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - edge "github.com/IBM/compliance-to-policy/controllers/edge.kcp.io/v1alpha1" - "github.com/IBM/compliance-to-policy/controllers/utils/kcpclient" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/oscal" - internalcompliance "github.com/IBM/compliance-to-policy/pkg/types/internalcompliance" - typesoscal "github.com/IBM/compliance-to-policy/pkg/types/oscal" - cd "github.com/IBM/compliance-to-policy/pkg/types/oscal/componentdefinition" "github.com/go-logr/logr" + c2pv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + edge "github.com/oscal-compass/compliance-to-policy/go/controllers/edge.kcp.io/v1alpha1" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/kcpclient" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/oscal" + internalcompliance "github.com/oscal-compass/compliance-to-policy/go/pkg/types/internalcompliance" + typesoscal "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal" + cd "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/componentdefinition" "gopkg.in/src-d/go-git.v4" githttp "gopkg.in/src-d/go-git.v4/plumbing/transport/http" "k8s.io/apimachinery/pkg/api/errors" diff --git a/controllers/wgpolicyk8s.io/v1alpha1/clusterpolicyreport_types.go b/go/controllers/wgpolicyk8s.io/v1alpha1/clusterpolicyreport_types.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1alpha1/clusterpolicyreport_types.go rename to go/controllers/wgpolicyk8s.io/v1alpha1/clusterpolicyreport_types.go diff --git a/controllers/wgpolicyk8s.io/v1alpha1/doc.go b/go/controllers/wgpolicyk8s.io/v1alpha1/doc.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1alpha1/doc.go rename to go/controllers/wgpolicyk8s.io/v1alpha1/doc.go diff --git a/controllers/wgpolicyk8s.io/v1alpha1/groupversion_info.go b/go/controllers/wgpolicyk8s.io/v1alpha1/groupversion_info.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1alpha1/groupversion_info.go rename to go/controllers/wgpolicyk8s.io/v1alpha1/groupversion_info.go diff --git a/controllers/wgpolicyk8s.io/v1alpha1/policyreport_types.go b/go/controllers/wgpolicyk8s.io/v1alpha1/policyreport_types.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1alpha1/policyreport_types.go rename to go/controllers/wgpolicyk8s.io/v1alpha1/policyreport_types.go diff --git a/controllers/wgpolicyk8s.io/v1alpha1/zz_generated.deepcopy.go b/go/controllers/wgpolicyk8s.io/v1alpha1/zz_generated.deepcopy.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1alpha1/zz_generated.deepcopy.go rename to go/controllers/wgpolicyk8s.io/v1alpha1/zz_generated.deepcopy.go diff --git a/controllers/wgpolicyk8s.io/v1alpha2/clusterpolicyreport_types.go b/go/controllers/wgpolicyk8s.io/v1alpha2/clusterpolicyreport_types.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1alpha2/clusterpolicyreport_types.go rename to go/controllers/wgpolicyk8s.io/v1alpha2/clusterpolicyreport_types.go diff --git a/controllers/wgpolicyk8s.io/v1alpha2/doc.go b/go/controllers/wgpolicyk8s.io/v1alpha2/doc.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1alpha2/doc.go rename to go/controllers/wgpolicyk8s.io/v1alpha2/doc.go diff --git a/controllers/wgpolicyk8s.io/v1alpha2/groupversion_info.go b/go/controllers/wgpolicyk8s.io/v1alpha2/groupversion_info.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1alpha2/groupversion_info.go rename to go/controllers/wgpolicyk8s.io/v1alpha2/groupversion_info.go diff --git a/controllers/wgpolicyk8s.io/v1alpha2/policyreport_types.go b/go/controllers/wgpolicyk8s.io/v1alpha2/policyreport_types.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1alpha2/policyreport_types.go rename to go/controllers/wgpolicyk8s.io/v1alpha2/policyreport_types.go diff --git a/controllers/wgpolicyk8s.io/v1alpha2/zz_generated.deepcopy.go b/go/controllers/wgpolicyk8s.io/v1alpha2/zz_generated.deepcopy.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1alpha2/zz_generated.deepcopy.go rename to go/controllers/wgpolicyk8s.io/v1alpha2/zz_generated.deepcopy.go diff --git a/controllers/wgpolicyk8s.io/v1beta1/clusterpolicyreport_types.go b/go/controllers/wgpolicyk8s.io/v1beta1/clusterpolicyreport_types.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1beta1/clusterpolicyreport_types.go rename to go/controllers/wgpolicyk8s.io/v1beta1/clusterpolicyreport_types.go diff --git a/controllers/wgpolicyk8s.io/v1beta1/doc.go b/go/controllers/wgpolicyk8s.io/v1beta1/doc.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1beta1/doc.go rename to go/controllers/wgpolicyk8s.io/v1beta1/doc.go diff --git a/controllers/wgpolicyk8s.io/v1beta1/groupversion_info.go b/go/controllers/wgpolicyk8s.io/v1beta1/groupversion_info.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1beta1/groupversion_info.go rename to go/controllers/wgpolicyk8s.io/v1beta1/groupversion_info.go diff --git a/controllers/wgpolicyk8s.io/v1beta1/policyreport_types.go b/go/controllers/wgpolicyk8s.io/v1beta1/policyreport_types.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1beta1/policyreport_types.go rename to go/controllers/wgpolicyk8s.io/v1beta1/policyreport_types.go diff --git a/controllers/wgpolicyk8s.io/v1beta1/zz_generated.deepcopy.go b/go/controllers/wgpolicyk8s.io/v1beta1/zz_generated.deepcopy.go similarity index 100% rename from controllers/wgpolicyk8s.io/v1beta1/zz_generated.deepcopy.go rename to go/controllers/wgpolicyk8s.io/v1beta1/zz_generated.deepcopy.go diff --git a/docs/images/e2e-pm.drawio b/go/docs/images/e2e-pm.drawio similarity index 100% rename from docs/images/e2e-pm.drawio rename to go/docs/images/e2e-pm.drawio diff --git a/docs/images/e2e-pm.png b/go/docs/images/e2e-pm.png similarity index 100% rename from docs/images/e2e-pm.png rename to go/docs/images/e2e-pm.png diff --git a/docs/kyverno/README.md b/go/docs/kyverno/README.md similarity index 94% rename from docs/kyverno/README.md rename to go/docs/kyverno/README.md index 068f86b..7d349fa 100644 --- a/docs/kyverno/README.md +++ b/go/docs/kyverno/README.md @@ -2,7 +2,7 @@ ### Continuous Compliance by C2P -https://github.com/IBM/compliance-to-policy/assets/113283236/4b0b5357-4025-46c8-8d88-1f4c00538795 +https://github.com/oscal-compass/compliance-to-policy/assets/113283236/4b0b5357-4025-46c8-8d88-1f4c00538795 ### Usage of C2P CLI ``` @@ -26,7 +26,7 @@ Use "c2pcli kyverno [command] --help" for more information about a command. ### Prerequisites 1. Prepare Kyverno Policy Resources - - You can use [policy-resources for test](/pkg/testdata/kyverno/policy-resources) + - You can use [policy-resources for test](/go/pkg/testdata/kyverno/policy-resources) - For bring your own policies, please see [Bring your own Kyverno Policy Resources](#bring-your-own-kyverno-policy-resources) #### Convert OSCAL to Kyverno Policy diff --git a/docs/kyverno/kyverno-workflow.drawio b/go/docs/kyverno/kyverno-workflow.drawio similarity index 100% rename from docs/kyverno/kyverno-workflow.drawio rename to go/docs/kyverno/kyverno-workflow.drawio diff --git a/docs/kyverno/oscal-vs-kyverno-result-mapping.csv b/go/docs/kyverno/oscal-vs-kyverno-result-mapping.csv similarity index 100% rename from docs/kyverno/oscal-vs-kyverno-result-mapping.csv rename to go/docs/kyverno/oscal-vs-kyverno-result-mapping.csv diff --git a/docs/ocm/README.md b/go/docs/ocm/README.md similarity index 98% rename from docs/ocm/README.md rename to go/docs/ocm/README.md index e30501a..406109d 100644 --- a/docs/ocm/README.md +++ b/go/docs/ocm/README.md @@ -22,14 +22,14 @@ Use "c2pcli ocm [command] --help" for more information about a command. ### Prerequisites 1. Install [Policy Generator Plugin](https://github.com/open-cluster-management-io/policy-generator-plugin#as-a-kustomize-plugin) 1. Prepare OCM Policy Resources - - You can use [policy-resources for test](/pkg/testdata/ocm/policies) + - You can use [policy-resources for test](/go/pkg/testdata/ocm/policies) - You can also use [Policy Collection](https://github.com/open-cluster-management-io/policy-collection). Please see [C2P Decomposer](#c2p-decomposer) ### Manual end-to-end use case #### Outline 1. Create OSCAL Component Definition - - Use example one. In real cases, a user writes OSCAL by Authoring tool like [Trestle](https://ibm.github.io/compliance-trestle/)) + - Use example one. In real cases, a user writes OSCAL by Authoring tool like [Trestle](https://github.com/oscal-compass/compliance-trestle)) 1. Run oscal2policy to generate OCM Policies from OSCAL 1. Deploy generated OCM Policies to OCM Hub 1. Get OCM Policies from OCM Hub @@ -213,7 +213,7 @@ Decompose OCM poicy collection to kubernetes resources composing each OCM policy │   ├── kustomization.yaml ``` ### C2P Composer -Compose OCM Policy from policy resources from compliance information (for example, [compliance.yaml](cmd/compose/compliance.yaml)) +Compose OCM Policy from policy resources from compliance information (for example, [compliance.yaml](/go/cmd/compose/compliance.yaml)) 1. Run C2P Composer ``` diff --git a/docs/ocm/c2p-config.yaml b/go/docs/ocm/c2p-config.yaml similarity index 100% rename from docs/ocm/c2p-config.yaml rename to go/docs/ocm/c2p-config.yaml diff --git a/docs/ocm/final-outputs/assessment-results.json b/go/docs/ocm/final-outputs/assessment-results.json similarity index 100% rename from docs/ocm/final-outputs/assessment-results.json rename to go/docs/ocm/final-outputs/assessment-results.json diff --git a/docs/ocm/final-outputs/compliance-posture.md b/go/docs/ocm/final-outputs/compliance-posture.md similarity index 100% rename from docs/ocm/final-outputs/compliance-posture.md rename to go/docs/ocm/final-outputs/compliance-posture.md diff --git a/docs/ocm/final-outputs/ocm-policies/ConfigMap.c2p.c2p-parameters.yaml b/go/docs/ocm/final-outputs/ocm-policies/ConfigMap.c2p.c2p-parameters.yaml similarity index 100% rename from docs/ocm/final-outputs/ocm-policies/ConfigMap.c2p.c2p-parameters.yaml rename to go/docs/ocm/final-outputs/ocm-policies/ConfigMap.c2p.c2p-parameters.yaml diff --git a/docs/ocm/final-outputs/ocm-policies/Placement.c2p.placement-managed-kubernetes.yaml b/go/docs/ocm/final-outputs/ocm-policies/Placement.c2p.placement-managed-kubernetes.yaml similarity index 100% rename from docs/ocm/final-outputs/ocm-policies/Placement.c2p.placement-managed-kubernetes.yaml rename to go/docs/ocm/final-outputs/ocm-policies/Placement.c2p.placement-managed-kubernetes.yaml diff --git a/docs/ocm/final-outputs/ocm-policies/PlacementBinding.c2p.policy-set.yaml b/go/docs/ocm/final-outputs/ocm-policies/PlacementBinding.c2p.policy-set.yaml similarity index 100% rename from docs/ocm/final-outputs/ocm-policies/PlacementBinding.c2p.policy-set.yaml rename to go/docs/ocm/final-outputs/ocm-policies/PlacementBinding.c2p.policy-set.yaml diff --git a/docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-deployment.yaml b/go/docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-deployment.yaml similarity index 100% rename from docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-deployment.yaml rename to go/docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-deployment.yaml diff --git a/docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-high-scan.yaml b/go/docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-high-scan.yaml similarity index 100% rename from docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-high-scan.yaml rename to go/docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-high-scan.yaml diff --git a/docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-install-kyverno-from-manifests.yaml b/go/docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-install-kyverno-from-manifests.yaml similarity index 100% rename from docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-install-kyverno-from-manifests.yaml rename to go/docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-install-kyverno-from-manifests.yaml diff --git a/docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-kyverno-require-labels.yaml b/go/docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-kyverno-require-labels.yaml similarity index 100% rename from docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-kyverno-require-labels.yaml rename to go/docs/ocm/final-outputs/ocm-policies/Policy.c2p.policy-kyverno-require-labels.yaml diff --git a/docs/ocm/final-outputs/ocm-policies/PolicySet.c2p.managed-kubernetes.yaml b/go/docs/ocm/final-outputs/ocm-policies/PolicySet.c2p.managed-kubernetes.yaml similarity index 100% rename from docs/ocm/final-outputs/ocm-policies/PolicySet.c2p.managed-kubernetes.yaml rename to go/docs/ocm/final-outputs/ocm-policies/PolicySet.c2p.managed-kubernetes.yaml diff --git a/docs/ocm/images/manual-end-to-end-use-case.drawio b/go/docs/ocm/images/manual-end-to-end-use-case.drawio similarity index 100% rename from docs/ocm/images/manual-end-to-end-use-case.drawio rename to go/docs/ocm/images/manual-end-to-end-use-case.drawio diff --git a/docs/ocm/images/manual-end-to-end-use-case.png b/go/docs/ocm/images/manual-end-to-end-use-case.png similarity index 100% rename from docs/ocm/images/manual-end-to-end-use-case.png rename to go/docs/ocm/images/manual-end-to-end-use-case.png diff --git a/docs/ocm/oscal-ar-vs-ocm-status-mapping.csv b/go/docs/ocm/oscal-ar-vs-ocm-status-mapping.csv similarity index 100% rename from docs/ocm/oscal-ar-vs-ocm-status-mapping.csv rename to go/docs/ocm/oscal-ar-vs-ocm-status-mapping.csv diff --git a/docs/ocm/oscal/component-definition.csv b/go/docs/ocm/oscal/component-definition.csv similarity index 100% rename from docs/ocm/oscal/component-definition.csv rename to go/docs/ocm/oscal/component-definition.csv diff --git a/docs/ocm/oscal/component-definition.json b/go/docs/ocm/oscal/component-definition.json similarity index 100% rename from docs/ocm/oscal/component-definition.json rename to go/docs/ocm/oscal/component-definition.json diff --git a/docs/ocm/oscal/profile.json b/go/docs/ocm/oscal/profile.json similarity index 100% rename from docs/ocm/oscal/profile.json rename to go/docs/ocm/oscal/profile.json diff --git a/go.mod b/go/go.mod similarity index 99% rename from go.mod rename to go/go.mod index eb74e73..382a947 100644 --- a/go.mod +++ b/go/go.mod @@ -1,4 +1,4 @@ -module github.com/IBM/compliance-to-policy +module github.com/oscal-compass/compliance-to-policy/go go 1.19 diff --git a/go.sum b/go/go.sum similarity index 100% rename from go.sum rename to go/go.sum diff --git a/hack/add-header.sh b/go/hack/add-header.sh similarity index 100% rename from hack/add-header.sh rename to go/hack/add-header.sh diff --git a/hack/boilerplate.go.txt b/go/hack/boilerplate.go.txt similarity index 100% rename from hack/boilerplate.go.txt rename to go/hack/boilerplate.go.txt diff --git a/hack/boilerplate.sh.txt b/go/hack/boilerplate.sh.txt similarity index 100% rename from hack/boilerplate.sh.txt rename to go/hack/boilerplate.sh.txt diff --git a/hack/cleanup-tmp-files-in-tests.sh b/go/hack/cleanup-tmp-files-in-tests.sh similarity index 100% rename from hack/cleanup-tmp-files-in-tests.sh rename to go/hack/cleanup-tmp-files-in-tests.sh diff --git a/hack/format/format.py b/go/hack/format/format.py similarity index 100% rename from hack/format/format.py rename to go/hack/format/format.py diff --git a/hack/format/requirements.txt b/go/hack/format/requirements.txt similarity index 100% rename from hack/format/requirements.txt rename to go/hack/format/requirements.txt diff --git a/hack/policy-checker/.gitignore b/go/hack/policy-checker/.gitignore similarity index 100% rename from hack/policy-checker/.gitignore rename to go/hack/policy-checker/.gitignore diff --git a/hack/policy-checker/README.md b/go/hack/policy-checker/README.md similarity index 100% rename from hack/policy-checker/README.md rename to go/hack/policy-checker/README.md diff --git a/hack/policy-checker/check.py b/go/hack/policy-checker/check.py similarity index 100% rename from hack/policy-checker/check.py rename to go/hack/policy-checker/check.py diff --git a/hack/policy-checker/common.py b/go/hack/policy-checker/common.py similarity index 100% rename from hack/policy-checker/common.py rename to go/hack/policy-checker/common.py diff --git a/hack/policy-checker/list_generated_policies.py b/go/hack/policy-checker/list_generated_policies.py similarity index 100% rename from hack/policy-checker/list_generated_policies.py rename to go/hack/policy-checker/list_generated_policies.py diff --git a/hack/policy-checker/requirements.txt b/go/hack/policy-checker/requirements.txt similarity index 100% rename from hack/policy-checker/requirements.txt rename to go/hack/policy-checker/requirements.txt diff --git a/main.go b/go/main.go similarity index 88% rename from main.go rename to go/main.go index 1bf7d47..f7e12a9 100644 --- a/main.go +++ b/go/main.go @@ -34,15 +34,15 @@ import ( "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/log/zap" - compliancetopolicycontrollerv1alpha1 "github.com/IBM/compliance-to-policy/api/v1alpha1" - wgpolicyk8sv1alpha2 "github.com/IBM/compliance-to-policy/controllers/wgpolicyk8s.io/v1alpha2" - - "github.com/IBM/compliance-to-policy/controllers/compliancedeployment" - ctrlrefkcp "github.com/IBM/compliance-to-policy/controllers/controlreference/kcp" - ctrlrefocm "github.com/IBM/compliance-to-policy/controllers/controlreference/ocm" - "github.com/IBM/compliance-to-policy/controllers/resultcollector" - "github.com/IBM/compliance-to-policy/controllers/utils/ocmk8sclients" - "github.com/IBM/compliance-to-policy/pkg" + compliancetopolicycontrollerv1alpha1 "github.com/oscal-compass/compliance-to-policy/go/api/v1alpha1" + wgpolicyk8sv1alpha2 "github.com/oscal-compass/compliance-to-policy/go/controllers/wgpolicyk8s.io/v1alpha2" + + "github.com/oscal-compass/compliance-to-policy/go/controllers/compliancedeployment" + ctrlrefkcp "github.com/oscal-compass/compliance-to-policy/go/controllers/controlreference/kcp" + ctrlrefocm "github.com/oscal-compass/compliance-to-policy/go/controllers/controlreference/ocm" + "github.com/oscal-compass/compliance-to-policy/go/controllers/resultcollector" + "github.com/oscal-compass/compliance-to-policy/go/controllers/utils/ocmk8sclients" + "github.com/oscal-compass/compliance-to-policy/go/pkg" //+kubebuilder:scaffold:imports ) diff --git a/pkg/decomposer/decomposer.go b/go/pkg/decomposer/decomposer.go similarity index 94% rename from pkg/decomposer/decomposer.go rename to go/pkg/decomposer/decomposer.go index b9f7da2..b96e758 100644 --- a/pkg/decomposer/decomposer.go +++ b/go/pkg/decomposer/decomposer.go @@ -21,10 +21,10 @@ import ( "os" "path/filepath" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/tables/resources" - . "github.com/IBM/compliance-to-policy/pkg/types/internalcompliance" - "github.com/IBM/compliance-to-policy/pkg/types/policycomposition" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/tables/resources" + . "github.com/oscal-compass/compliance-to-policy/go/pkg/types/internalcompliance" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policycomposition" ) type Decomposer struct { diff --git a/pkg/gitutils.go b/go/pkg/gitutils.go similarity index 100% rename from pkg/gitutils.go rename to go/pkg/gitutils.go diff --git a/pkg/kyverno/configparser.go b/go/pkg/kyverno/configparser.go similarity index 91% rename from pkg/kyverno/configparser.go rename to go/pkg/kyverno/configparser.go index a85b70d..4a17525 100644 --- a/pkg/kyverno/configparser.go +++ b/go/pkg/kyverno/configparser.go @@ -19,10 +19,10 @@ package kyverno import ( "fmt" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/oscal" - "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" - typear "github.com/IBM/compliance-to-policy/pkg/types/oscal/assessmentresults" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/oscal" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" + typear "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/assessmentresults" "go.uber.org/zap" ) diff --git a/pkg/kyverno/fileloader.go b/go/pkg/kyverno/fileloader.go similarity index 98% rename from pkg/kyverno/fileloader.go rename to go/pkg/kyverno/fileloader.go index 13f564a..82cb07c 100644 --- a/pkg/kyverno/fileloader.go +++ b/go/pkg/kyverno/fileloader.go @@ -23,7 +23,7 @@ import ( "regexp" "strings" - "github.com/IBM/compliance-to-policy/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg" "go.uber.org/zap" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) diff --git a/pkg/kyverno/oscal2policy.go b/go/pkg/kyverno/oscal2policy.go similarity index 92% rename from pkg/kyverno/oscal2policy.go rename to go/pkg/kyverno/oscal2policy.go index 788b85f..30eef22 100644 --- a/pkg/kyverno/oscal2policy.go +++ b/go/pkg/kyverno/oscal2policy.go @@ -19,8 +19,8 @@ package kyverno import ( "fmt" - "github.com/IBM/compliance-to-policy/pkg" - typec2pcr "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + typec2pcr "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" cp "github.com/otiai10/copy" "go.uber.org/zap" ) diff --git a/pkg/kyverno/oscal2policy_test.go b/go/pkg/kyverno/oscal2policy_test.go similarity index 94% rename from pkg/kyverno/oscal2policy_test.go rename to go/pkg/kyverno/oscal2policy_test.go index 8dc2d5c..60dd6a3 100644 --- a/pkg/kyverno/oscal2policy_test.go +++ b/go/pkg/kyverno/oscal2policy_test.go @@ -20,8 +20,8 @@ import ( "os" "testing" - "github.com/IBM/compliance-to-policy/pkg" - typec2pcr "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + typec2pcr "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" "github.com/stretchr/testify/assert" ) diff --git a/pkg/kyverno/result2oscal.go b/go/pkg/kyverno/result2oscal.go similarity index 95% rename from pkg/kyverno/result2oscal.go rename to go/pkg/kyverno/result2oscal.go index 7cb7500..eb9c485 100644 --- a/pkg/kyverno/result2oscal.go +++ b/go/pkg/kyverno/result2oscal.go @@ -21,12 +21,12 @@ import ( "strings" "time" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/oscal" - typec2pcr "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" - typear "github.com/IBM/compliance-to-policy/pkg/types/oscal/assessmentresults" - typeoscalcommon "github.com/IBM/compliance-to-policy/pkg/types/oscal/common" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/oscal" + typec2pcr "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" + typear "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/assessmentresults" + typeoscalcommon "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/common" "go.uber.org/zap" "k8s.io/apimachinery/pkg/util/sets" typepolr "sigs.k8s.io/wg-policy-prototypes/policy-report/pkg/api/wgpolicyk8s.io/v1beta1" diff --git a/pkg/ocm/configparser.go b/go/pkg/ocm/configparser.go similarity index 92% rename from pkg/ocm/configparser.go rename to go/pkg/ocm/configparser.go index 2ce0fed..68eb14d 100644 --- a/pkg/ocm/configparser.go +++ b/go/pkg/ocm/configparser.go @@ -19,9 +19,9 @@ package ocm import ( "fmt" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/oscal" - "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/oscal" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" ) type C2PCRParser struct { diff --git a/pkg/ocm/helper.go b/go/pkg/ocm/helper.go similarity index 95% rename from pkg/ocm/helper.go rename to go/pkg/ocm/helper.go index c99ef5f..3b12ea4 100644 --- a/pkg/ocm/helper.go +++ b/go/pkg/ocm/helper.go @@ -17,8 +17,8 @@ limitations under the License. package ocm import ( - typeconfigpolicy "github.com/IBM/compliance-to-policy/pkg/types/configurationpolicy" - typepolicy "github.com/IBM/compliance-to-policy/pkg/types/policy" + typeconfigpolicy "github.com/oscal-compass/compliance-to-policy/go/pkg/types/configurationpolicy" + typepolicy "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policy" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" typepolr "sigs.k8s.io/wg-policy-prototypes/policy-report/pkg/api/wgpolicyk8s.io/v1beta1" ) diff --git a/pkg/ocm/oscal2policy.go b/go/pkg/ocm/oscal2policy.go similarity index 96% rename from pkg/ocm/oscal2policy.go rename to go/pkg/ocm/oscal2policy.go index 4ce0bea..a49accb 100644 --- a/pkg/ocm/oscal2policy.go +++ b/go/pkg/ocm/oscal2policy.go @@ -24,11 +24,11 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/oscal" - policygenerator "github.com/IBM/compliance-to-policy/pkg/policygenerator" - typec2pcr "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" - pgtype "github.com/IBM/compliance-to-policy/pkg/types/policygenerator" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/oscal" + policygenerator "github.com/oscal-compass/compliance-to-policy/go/pkg/policygenerator" + typec2pcr "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" + pgtype "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policygenerator" cp "github.com/otiai10/copy" "go.uber.org/zap" "sigs.k8s.io/kustomize/api/resmap" diff --git a/pkg/ocm/oscal2policy_test.go b/go/pkg/ocm/oscal2policy_test.go similarity index 94% rename from pkg/ocm/oscal2policy_test.go rename to go/pkg/ocm/oscal2policy_test.go index 1e62d8f..a3e45f5 100644 --- a/pkg/ocm/oscal2policy_test.go +++ b/go/pkg/ocm/oscal2policy_test.go @@ -20,8 +20,8 @@ import ( "os" "testing" - "github.com/IBM/compliance-to-policy/pkg" - typec2pcr "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + typec2pcr "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" "github.com/stretchr/testify/assert" ) diff --git a/pkg/ocm/result2oscal.go b/go/pkg/ocm/result2oscal.go similarity index 92% rename from pkg/ocm/result2oscal.go rename to go/pkg/ocm/result2oscal.go index b7e6a5b..858865c 100644 --- a/pkg/ocm/result2oscal.go +++ b/go/pkg/ocm/result2oscal.go @@ -20,19 +20,19 @@ import ( "fmt" "time" - "github.com/IBM/compliance-to-policy/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg" sigyaml "sigs.k8s.io/yaml" "k8s.io/apimachinery/pkg/util/sets" - "github.com/IBM/compliance-to-policy/pkg/oscal" - typec2pcr "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" - typear "github.com/IBM/compliance-to-policy/pkg/types/oscal/assessmentresults" - typeoscalcommon "github.com/IBM/compliance-to-policy/pkg/types/oscal/common" - typeplacementdecision "github.com/IBM/compliance-to-policy/pkg/types/placementdecision" - typepolicy "github.com/IBM/compliance-to-policy/pkg/types/policy" - typereport "github.com/IBM/compliance-to-policy/pkg/types/report" - typeutils "github.com/IBM/compliance-to-policy/pkg/types/utils" + "github.com/oscal-compass/compliance-to-policy/go/pkg/oscal" + typec2pcr "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" + typear "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/assessmentresults" + typeoscalcommon "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/common" + typeplacementdecision "github.com/oscal-compass/compliance-to-policy/go/pkg/types/placementdecision" + typepolicy "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policy" + typereport "github.com/oscal-compass/compliance-to-policy/go/pkg/types/report" + typeutils "github.com/oscal-compass/compliance-to-policy/go/pkg/types/utils" ) type ResultToOscal struct { diff --git a/pkg/ocm/result2oscal_test.go b/go/pkg/ocm/result2oscal_test.go similarity index 92% rename from pkg/ocm/result2oscal_test.go rename to go/pkg/ocm/result2oscal_test.go index b8b6226..33b7ca0 100644 --- a/pkg/ocm/result2oscal_test.go +++ b/go/pkg/ocm/result2oscal_test.go @@ -20,11 +20,11 @@ import ( "os" "testing" - "github.com/IBM/compliance-to-policy/pkg" - typec2pcr "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" - typear "github.com/IBM/compliance-to-policy/pkg/types/oscal/assessmentresults" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + typec2pcr "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" + typear "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/assessmentresults" "github.com/stretchr/testify/assert" ) diff --git a/pkg/oscal/oscal.go b/go/pkg/oscal/oscal.go similarity index 95% rename from pkg/oscal/oscal.go rename to go/pkg/oscal/oscal.go index 99e1d3f..d860ce4 100644 --- a/pkg/oscal/oscal.go +++ b/go/pkg/oscal/oscal.go @@ -19,13 +19,13 @@ package oscal import ( "strings" - "github.com/IBM/compliance-to-policy/pkg/decomposer" - "github.com/IBM/compliance-to-policy/pkg/tables/resources" - "github.com/IBM/compliance-to-policy/pkg/types/internalcompliance" - "github.com/IBM/compliance-to-policy/pkg/types/oscal" - typecommon "github.com/IBM/compliance-to-policy/pkg/types/oscal/common" - cd "github.com/IBM/compliance-to-policy/pkg/types/oscal/componentdefinition" "github.com/google/uuid" + "github.com/oscal-compass/compliance-to-policy/go/pkg/decomposer" + "github.com/oscal-compass/compliance-to-policy/go/pkg/tables/resources" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/internalcompliance" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal" + typecommon "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/common" + cd "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/componentdefinition" ) var standardFromPolicyCollectionToOscal map[string]string = map[string]string{ diff --git a/pkg/oscal/oscal_test.go b/go/pkg/oscal/oscal_test.go similarity index 94% rename from pkg/oscal/oscal_test.go rename to go/pkg/oscal/oscal_test.go index 81d1117..b20a8b0 100644 --- a/pkg/oscal/oscal_test.go +++ b/go/pkg/oscal/oscal_test.go @@ -24,11 +24,11 @@ import ( "strings" "testing" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/tables/resources" - "github.com/IBM/compliance-to-policy/pkg/types/internalcompliance" - "github.com/IBM/compliance-to-policy/pkg/types/oscal" - cd "github.com/IBM/compliance-to-policy/pkg/types/oscal/componentdefinition" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/tables/resources" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/internalcompliance" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal" + cd "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/componentdefinition" "github.com/stretchr/testify/assert" ) @@ -106,7 +106,7 @@ func TestTrestleCsv(t *testing.T) { ComponentDescription: "Description ...", ComponentType: "Service", } - namespace := "https://github.com/IBM/compliance-to-policy" + namespace := "https://github.com/oscal-compass/compliance-to-policy/go" trestlCsvRowsMap := makeTrestleCsvFromMasterData(componentProps, namespace, resourceTable) t.Log(trestlCsvRowsMap) diff --git a/pkg/oscal/parser.go b/go/pkg/oscal/parser.go similarity index 97% rename from pkg/oscal/parser.go rename to go/pkg/oscal/parser.go index 3e77e3f..56ad207 100644 --- a/pkg/oscal/parser.go +++ b/go/pkg/oscal/parser.go @@ -17,7 +17,7 @@ limitations under the License. package oscal import ( - . "github.com/IBM/compliance-to-policy/pkg/types/oscal/componentdefinition" + . "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/componentdefinition" ) type RuleObject struct { diff --git a/pkg/oscal/testdata/NIST_SP-800-53_rev5_HIGH-baseline_profile.json b/go/pkg/oscal/testdata/NIST_SP-800-53_rev5_HIGH-baseline_profile.json similarity index 100% rename from pkg/oscal/testdata/NIST_SP-800-53_rev5_HIGH-baseline_profile.json rename to go/pkg/oscal/testdata/NIST_SP-800-53_rev5_HIGH-baseline_profile.json diff --git a/pkg/oscal/testdata/NIST_SP-800-53_rev5_LOW-baseline_profile.json b/go/pkg/oscal/testdata/NIST_SP-800-53_rev5_LOW-baseline_profile.json similarity index 100% rename from pkg/oscal/testdata/NIST_SP-800-53_rev5_LOW-baseline_profile.json rename to go/pkg/oscal/testdata/NIST_SP-800-53_rev5_LOW-baseline_profile.json diff --git a/pkg/oscal/testdata/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json b/go/pkg/oscal/testdata/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json similarity index 100% rename from pkg/oscal/testdata/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json rename to go/pkg/oscal/testdata/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json diff --git a/pkg/oscal/testdata/NIST_SP-800-53_rev5_catalog.json b/go/pkg/oscal/testdata/NIST_SP-800-53_rev5_catalog.json similarity index 100% rename from pkg/oscal/testdata/NIST_SP-800-53_rev5_catalog.json rename to go/pkg/oscal/testdata/NIST_SP-800-53_rev5_catalog.json diff --git a/pkg/oscal/testdata/component-definition.json b/go/pkg/oscal/testdata/component-definition.json similarity index 100% rename from pkg/oscal/testdata/component-definition.json rename to go/pkg/oscal/testdata/component-definition.json diff --git a/pkg/oscal/testdata/resources.csv b/go/pkg/oscal/testdata/resources.csv similarity index 100% rename from pkg/oscal/testdata/resources.csv rename to go/pkg/oscal/testdata/resources.csv diff --git a/pkg/oscal/testdata/results/interna-oscal-standards-high.yaml b/go/pkg/oscal/testdata/results/interna-oscal-standards-high.yaml similarity index 100% rename from pkg/oscal/testdata/results/interna-oscal-standards-high.yaml rename to go/pkg/oscal/testdata/results/interna-oscal-standards-high.yaml diff --git a/pkg/oscal/testdata/results/interna-oscal-standards-low.yaml b/go/pkg/oscal/testdata/results/interna-oscal-standards-low.yaml similarity index 100% rename from pkg/oscal/testdata/results/interna-oscal-standards-low.yaml rename to go/pkg/oscal/testdata/results/interna-oscal-standards-low.yaml diff --git a/pkg/oscal/testdata/results/interna-oscal-standards-moderate.yaml b/go/pkg/oscal/testdata/results/interna-oscal-standards-moderate.yaml similarity index 100% rename from pkg/oscal/testdata/results/interna-oscal-standards-moderate.yaml rename to go/pkg/oscal/testdata/results/interna-oscal-standards-moderate.yaml diff --git a/pkg/oscal/testdata/results/interna-oscal-standards.yaml b/go/pkg/oscal/testdata/results/interna-oscal-standards.yaml similarity index 100% rename from pkg/oscal/testdata/results/interna-oscal-standards.yaml rename to go/pkg/oscal/testdata/results/interna-oscal-standards.yaml diff --git a/pkg/oscal/testdata/results/internal-compliance-from-cd.yaml b/go/pkg/oscal/testdata/results/internal-compliance-from-cd.yaml similarity index 100% rename from pkg/oscal/testdata/results/internal-compliance-from-cd.yaml rename to go/pkg/oscal/testdata/results/internal-compliance-from-cd.yaml diff --git a/pkg/oscal/testdata/results/internal-compliance.yaml b/go/pkg/oscal/testdata/results/internal-compliance.yaml similarity index 100% rename from pkg/oscal/testdata/results/internal-compliance.yaml rename to go/pkg/oscal/testdata/results/internal-compliance.yaml diff --git a/pkg/parser/parser.go b/go/pkg/parser/parser.go similarity index 94% rename from pkg/parser/parser.go rename to go/pkg/parser/parser.go index 36e746d..a5b83a7 100644 --- a/pkg/parser/parser.go +++ b/go/pkg/parser/parser.go @@ -23,13 +23,13 @@ import ( "path/filepath" "strings" - "github.com/IBM/compliance-to-policy/pkg" - "github.com/IBM/compliance-to-policy/pkg/policygenerator" - "github.com/IBM/compliance-to-policy/pkg/tables" - "github.com/IBM/compliance-to-policy/pkg/tables/resources" - "github.com/IBM/compliance-to-policy/pkg/types/configurationpolicy" - "github.com/IBM/compliance-to-policy/pkg/types/policy" - typepolicygenerator "github.com/IBM/compliance-to-policy/pkg/types/policygenerator" + "github.com/oscal-compass/compliance-to-policy/go/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg/policygenerator" + "github.com/oscal-compass/compliance-to-policy/go/pkg/tables" + "github.com/oscal-compass/compliance-to-policy/go/pkg/tables/resources" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/configurationpolicy" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policy" + typepolicygenerator "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policygenerator" "go.uber.org/zap" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" utilyaml "k8s.io/apimachinery/pkg/util/yaml" diff --git a/pkg/parser/parser_test.go b/go/pkg/parser/parser_test.go similarity index 94% rename from pkg/parser/parser_test.go rename to go/pkg/parser/parser_test.go index 4028bf5..75958e2 100644 --- a/pkg/parser/parser_test.go +++ b/go/pkg/parser/parser_test.go @@ -21,7 +21,7 @@ import ( "os" "testing" - "github.com/IBM/compliance-to-policy/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg" ) //go:embed testdata/* diff --git a/pkg/parser/testdata/expected/policies.csv b/go/pkg/parser/testdata/expected/policies.csv similarity index 100% rename from pkg/parser/testdata/expected/policies.csv rename to go/pkg/parser/testdata/expected/policies.csv diff --git a/pkg/parser/testdata/expected/resources.csv b/go/pkg/parser/testdata/expected/resources.csv similarity index 100% rename from pkg/parser/testdata/expected/resources.csv rename to go/pkg/parser/testdata/expected/resources.csv diff --git a/pkg/parser/testdata/policy.yaml b/go/pkg/parser/testdata/policy.yaml similarity index 100% rename from pkg/parser/testdata/policy.yaml rename to go/pkg/parser/testdata/policy.yaml diff --git a/pkg/parser/util.go b/go/pkg/parser/util.go similarity index 100% rename from pkg/parser/util.go rename to go/pkg/parser/util.go diff --git a/pkg/parser/yamlloder.go b/go/pkg/parser/yamlloder.go similarity index 94% rename from pkg/parser/yamlloder.go rename to go/pkg/parser/yamlloder.go index 72a625d..dfe7ddc 100644 --- a/pkg/parser/yamlloder.go +++ b/go/pkg/parser/yamlloder.go @@ -20,8 +20,8 @@ import ( "errors" "io" - "github.com/IBM/compliance-to-policy/pkg/types/placements" - "github.com/IBM/compliance-to-policy/pkg/types/policy" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/placements" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policy" "gopkg.in/yaml.v3" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" k8syaml "k8s.io/apimachinery/pkg/runtime/serializer/yaml" diff --git a/pkg/parser/yamlloder_test.go b/go/pkg/parser/yamlloder_test.go similarity index 92% rename from pkg/parser/yamlloder_test.go rename to go/pkg/parser/yamlloder_test.go index 435225b..eee4fba 100644 --- a/pkg/parser/yamlloder_test.go +++ b/go/pkg/parser/yamlloder_test.go @@ -19,8 +19,8 @@ package parser import ( "testing" - "github.com/IBM/compliance-to-policy/pkg/types/placements" - "github.com/IBM/compliance-to-policy/pkg/types/policy" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/placements" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policy" "gopkg.in/yaml.v3" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" k8syaml "k8s.io/apimachinery/pkg/runtime/serializer/yaml" diff --git a/pkg/policygenerator/policygenerator.go b/go/pkg/policygenerator/policygenerator.go similarity index 97% rename from pkg/policygenerator/policygenerator.go rename to go/pkg/policygenerator/policygenerator.go index 6f5a3c0..d098540 100644 --- a/pkg/policygenerator/policygenerator.go +++ b/go/pkg/policygenerator/policygenerator.go @@ -17,7 +17,7 @@ limitations under the License. package policygenerator import ( - "github.com/IBM/compliance-to-policy/pkg/types/policygenerator" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/policygenerator" "sigs.k8s.io/kustomize/api/krusty" "sigs.k8s.io/kustomize/api/resmap" kustomizetypes "sigs.k8s.io/kustomize/api/types" diff --git a/pkg/policygenerator/policygenerator_test.go b/go/pkg/policygenerator/policygenerator_test.go similarity index 96% rename from pkg/policygenerator/policygenerator_test.go rename to go/pkg/policygenerator/policygenerator_test.go index 319e124..3855c35 100644 --- a/pkg/policygenerator/policygenerator_test.go +++ b/go/pkg/policygenerator/policygenerator_test.go @@ -20,7 +20,7 @@ import ( "fmt" "testing" - "github.com/IBM/compliance-to-policy/pkg" + "github.com/oscal-compass/compliance-to-policy/go/pkg" "sigs.k8s.io/kustomize/api/krusty" "sigs.k8s.io/kustomize/api/types" ) diff --git a/pkg/policygenerator/testdata/input-kustomize/base/kustomization.yaml b/go/pkg/policygenerator/testdata/input-kustomize/base/kustomization.yaml similarity index 100% rename from pkg/policygenerator/testdata/input-kustomize/base/kustomization.yaml rename to go/pkg/policygenerator/testdata/input-kustomize/base/kustomization.yaml diff --git a/pkg/policygenerator/testdata/input-kustomize/base/nginx-pod.yaml b/go/pkg/policygenerator/testdata/input-kustomize/base/nginx-pod.yaml similarity index 100% rename from pkg/policygenerator/testdata/input-kustomize/base/nginx-pod.yaml rename to go/pkg/policygenerator/testdata/input-kustomize/base/nginx-pod.yaml diff --git a/pkg/policygenerator/testdata/input-kustomize/dev/kustomization.yml b/go/pkg/policygenerator/testdata/input-kustomize/dev/kustomization.yml similarity index 100% rename from pkg/policygenerator/testdata/input-kustomize/dev/kustomization.yml rename to go/pkg/policygenerator/testdata/input-kustomize/dev/kustomization.yml diff --git a/pkg/policygenerator/testdata/input-kustomize/kustomization.yml b/go/pkg/policygenerator/testdata/input-kustomize/kustomization.yml similarity index 100% rename from pkg/policygenerator/testdata/input-kustomize/kustomization.yml rename to go/pkg/policygenerator/testdata/input-kustomize/kustomization.yml diff --git a/pkg/policygenerator/testdata/input-kustomize/prod/kustomization.yml b/go/pkg/policygenerator/testdata/input-kustomize/prod/kustomization.yml similarity index 100% rename from pkg/policygenerator/testdata/input-kustomize/prod/kustomization.yml rename to go/pkg/policygenerator/testdata/input-kustomize/prod/kustomization.yml diff --git a/pkg/policygenerator/testdata/kustomization.yml b/go/pkg/policygenerator/testdata/kustomization.yml similarity index 100% rename from pkg/policygenerator/testdata/kustomization.yml rename to go/pkg/policygenerator/testdata/kustomization.yml diff --git a/pkg/policygenerator/testdata/policyGenerator-kustomize.yaml b/go/pkg/policygenerator/testdata/policyGenerator-kustomize.yaml similarity index 100% rename from pkg/policygenerator/testdata/policyGenerator-kustomize.yaml rename to go/pkg/policygenerator/testdata/policyGenerator-kustomize.yaml diff --git a/pkg/pvpcommon/oscal2posture.go b/go/pkg/pvpcommon/oscal2posture.go similarity index 91% rename from pkg/pvpcommon/oscal2posture.go rename to go/pkg/pvpcommon/oscal2posture.go index 1ecf3cf..d3df0fa 100644 --- a/pkg/pvpcommon/oscal2posture.go +++ b/go/pkg/pvpcommon/oscal2posture.go @@ -25,11 +25,11 @@ import ( "go.uber.org/zap" - "github.com/IBM/compliance-to-policy/pkg/oscal" - tp "github.com/IBM/compliance-to-policy/pkg/pvpcommon/template" - typec2pcr "github.com/IBM/compliance-to-policy/pkg/types/c2pcr" - typear "github.com/IBM/compliance-to-policy/pkg/types/oscal/assessmentresults" - typecd "github.com/IBM/compliance-to-policy/pkg/types/oscal/componentdefinition" + "github.com/oscal-compass/compliance-to-policy/go/pkg/oscal" + tp "github.com/oscal-compass/compliance-to-policy/go/pkg/pvpcommon/template" + typec2pcr "github.com/oscal-compass/compliance-to-policy/go/pkg/types/c2pcr" + typear "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/assessmentresults" + typecd "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/componentdefinition" ) //go:embed template/*.md diff --git a/pkg/pvpcommon/template/model.go b/go/pkg/pvpcommon/template/model.go similarity index 100% rename from pkg/pvpcommon/template/model.go rename to go/pkg/pvpcommon/template/model.go diff --git a/pkg/pvpcommon/template/template.md b/go/pkg/pvpcommon/template/template.md similarity index 100% rename from pkg/pvpcommon/template/template.md rename to go/pkg/pvpcommon/template/template.md diff --git a/pkg/tables/resources/resource-table.go b/go/pkg/tables/resources/resource-table.go similarity index 98% rename from pkg/tables/resources/resource-table.go rename to go/pkg/tables/resources/resource-table.go index 6450dc1..d51cdae 100644 --- a/pkg/tables/resources/resource-table.go +++ b/go/pkg/tables/resources/resource-table.go @@ -22,8 +22,8 @@ import ( "os" "strings" - "github.com/IBM/compliance-to-policy/pkg" "github.com/olekukonko/tablewriter" + "github.com/oscal-compass/compliance-to-policy/go/pkg" "go.uber.org/zap" ) diff --git a/pkg/tables/table.go b/go/pkg/tables/table.go similarity index 100% rename from pkg/tables/table.go rename to go/pkg/tables/table.go diff --git a/pkg/testdata/compliance.yaml b/go/pkg/testdata/compliance.yaml similarity index 100% rename from pkg/testdata/compliance.yaml rename to go/pkg/testdata/compliance.yaml diff --git a/pkg/testdata/kyverno/c2p-config.yaml b/go/pkg/testdata/kyverno/c2p-config.yaml similarity index 100% rename from pkg/testdata/kyverno/c2p-config.yaml rename to go/pkg/testdata/kyverno/c2p-config.yaml diff --git a/pkg/testdata/kyverno/component-definition.json b/go/pkg/testdata/kyverno/component-definition.json similarity index 100% rename from pkg/testdata/kyverno/component-definition.json rename to go/pkg/testdata/kyverno/component-definition.json diff --git a/pkg/testdata/kyverno/policy-reports/clusterpolicies.kyverno.io.yaml b/go/pkg/testdata/kyverno/policy-reports/clusterpolicies.kyverno.io.yaml similarity index 100% rename from pkg/testdata/kyverno/policy-reports/clusterpolicies.kyverno.io.yaml rename to go/pkg/testdata/kyverno/policy-reports/clusterpolicies.kyverno.io.yaml diff --git a/pkg/testdata/kyverno/policy-reports/clusterpolicyreports.wgpolicyk8s.io.yaml b/go/pkg/testdata/kyverno/policy-reports/clusterpolicyreports.wgpolicyk8s.io.yaml similarity index 100% rename from pkg/testdata/kyverno/policy-reports/clusterpolicyreports.wgpolicyk8s.io.yaml rename to go/pkg/testdata/kyverno/policy-reports/clusterpolicyreports.wgpolicyk8s.io.yaml diff --git a/pkg/testdata/kyverno/policy-reports/policies.kyverno.io.yaml b/go/pkg/testdata/kyverno/policy-reports/policies.kyverno.io.yaml similarity index 100% rename from pkg/testdata/kyverno/policy-reports/policies.kyverno.io.yaml rename to go/pkg/testdata/kyverno/policy-reports/policies.kyverno.io.yaml diff --git a/pkg/testdata/kyverno/policy-reports/policyreports.wgpolicyk8s.io.yaml b/go/pkg/testdata/kyverno/policy-reports/policyreports.wgpolicyk8s.io.yaml similarity index 100% rename from pkg/testdata/kyverno/policy-reports/policyreports.wgpolicyk8s.io.yaml rename to go/pkg/testdata/kyverno/policy-reports/policyreports.wgpolicyk8s.io.yaml diff --git a/pkg/testdata/kyverno/policy-resources/allowed-base-images/02-setup-cm.yaml b/go/pkg/testdata/kyverno/policy-resources/allowed-base-images/02-setup-cm.yaml similarity index 100% rename from pkg/testdata/kyverno/policy-resources/allowed-base-images/02-setup-cm.yaml rename to go/pkg/testdata/kyverno/policy-resources/allowed-base-images/02-setup-cm.yaml diff --git a/pkg/testdata/kyverno/policy-resources/allowed-base-images/allowed-base-images.yaml b/go/pkg/testdata/kyverno/policy-resources/allowed-base-images/allowed-base-images.yaml similarity index 100% rename from pkg/testdata/kyverno/policy-resources/allowed-base-images/allowed-base-images.yaml rename to go/pkg/testdata/kyverno/policy-resources/allowed-base-images/allowed-base-images.yaml diff --git a/pkg/testdata/ocm/assessment-results.json b/go/pkg/testdata/ocm/assessment-results.json similarity index 100% rename from pkg/testdata/ocm/assessment-results.json rename to go/pkg/testdata/ocm/assessment-results.json diff --git a/pkg/testdata/ocm/catalog.json b/go/pkg/testdata/ocm/catalog.json similarity index 100% rename from pkg/testdata/ocm/catalog.json rename to go/pkg/testdata/ocm/catalog.json diff --git a/pkg/testdata/ocm/component-definition.json b/go/pkg/testdata/ocm/component-definition.json similarity index 100% rename from pkg/testdata/ocm/component-definition.json rename to go/pkg/testdata/ocm/component-definition.json diff --git a/pkg/testdata/ocm/policies/add-chrony/add-chrony-worker/MachineConfig.50-worker-chrony.0.yaml b/go/pkg/testdata/ocm/policies/add-chrony/add-chrony-worker/MachineConfig.50-worker-chrony.0.yaml similarity index 100% rename from pkg/testdata/ocm/policies/add-chrony/add-chrony-worker/MachineConfig.50-worker-chrony.0.yaml rename to go/pkg/testdata/ocm/policies/add-chrony/add-chrony-worker/MachineConfig.50-worker-chrony.0.yaml diff --git a/pkg/testdata/ocm/policies/add-chrony/kustomization.yaml b/go/pkg/testdata/ocm/policies/add-chrony/kustomization.yaml similarity index 100% rename from pkg/testdata/ocm/policies/add-chrony/kustomization.yaml rename to go/pkg/testdata/ocm/policies/add-chrony/kustomization.yaml diff --git a/pkg/testdata/ocm/policies/add-chrony/policy-generator.yaml b/go/pkg/testdata/ocm/policies/add-chrony/policy-generator.yaml similarity index 100% rename from pkg/testdata/ocm/policies/add-chrony/policy-generator.yaml rename to go/pkg/testdata/ocm/policies/add-chrony/policy-generator.yaml diff --git a/pkg/testdata/ocm/policies/install-odf-lvm-operator/kustomization.yaml b/go/pkg/testdata/ocm/policies/install-odf-lvm-operator/kustomization.yaml similarity index 100% rename from pkg/testdata/ocm/policies/install-odf-lvm-operator/kustomization.yaml rename to go/pkg/testdata/ocm/policies/install-odf-lvm-operator/kustomization.yaml diff --git a/pkg/testdata/ocm/policies/install-odf-lvm-operator/odf-lvmcluster/LVMCluster.odf-lvmcluster.0.yaml b/go/pkg/testdata/ocm/policies/install-odf-lvm-operator/odf-lvmcluster/LVMCluster.odf-lvmcluster.0.yaml similarity index 100% rename from pkg/testdata/ocm/policies/install-odf-lvm-operator/odf-lvmcluster/LVMCluster.odf-lvmcluster.0.yaml rename to go/pkg/testdata/ocm/policies/install-odf-lvm-operator/odf-lvmcluster/LVMCluster.odf-lvmcluster.0.yaml diff --git a/pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-generator.yaml b/go/pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-generator.yaml similarity index 100% rename from pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-generator.yaml rename to go/pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-generator.yaml diff --git a/pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Namespace.openshift-storage.0.yaml b/go/pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Namespace.openshift-storage.0.yaml similarity index 100% rename from pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Namespace.openshift-storage.0.yaml rename to go/pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Namespace.openshift-storage.0.yaml diff --git a/pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/OperatorGroup.openshift-storage-operatorgroup.0.yaml b/go/pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/OperatorGroup.openshift-storage-operatorgroup.0.yaml similarity index 100% rename from pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/OperatorGroup.openshift-storage-operatorgroup.0.yaml rename to go/pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/OperatorGroup.openshift-storage-operatorgroup.0.yaml diff --git a/pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Subscription.lvm-operator.0.yaml b/go/pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Subscription.lvm-operator.0.yaml similarity index 100% rename from pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Subscription.lvm-operator.0.yaml rename to go/pkg/testdata/ocm/policies/install-odf-lvm-operator/policy-odf-lvm-operator/Subscription.lvm-operator.0.yaml diff --git a/pkg/testdata/ocm/policies/policy-deployment/kustomization.yaml b/go/pkg/testdata/ocm/policies/policy-deployment/kustomization.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-deployment/kustomization.yaml rename to go/pkg/testdata/ocm/policies/policy-deployment/kustomization.yaml diff --git a/pkg/testdata/ocm/policies/policy-deployment/policy-generator.yaml b/go/pkg/testdata/ocm/policies/policy-deployment/policy-generator.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-deployment/policy-generator.yaml rename to go/pkg/testdata/ocm/policies/policy-deployment/policy-generator.yaml diff --git a/pkg/testdata/ocm/policies/policy-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml b/go/pkg/testdata/ocm/policies/policy-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml rename to go/pkg/testdata/ocm/policies/policy-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml diff --git a/pkg/testdata/ocm/policies/policy-disallowed-roles/kustomization.yaml b/go/pkg/testdata/ocm/policies/policy-disallowed-roles/kustomization.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-disallowed-roles/kustomization.yaml rename to go/pkg/testdata/ocm/policies/policy-disallowed-roles/kustomization.yaml diff --git a/pkg/testdata/ocm/policies/policy-disallowed-roles/policy-disallowed-roles-sample-role/Role.noname.0.yaml b/go/pkg/testdata/ocm/policies/policy-disallowed-roles/policy-disallowed-roles-sample-role/Role.noname.0.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-disallowed-roles/policy-disallowed-roles-sample-role/Role.noname.0.yaml rename to go/pkg/testdata/ocm/policies/policy-disallowed-roles/policy-disallowed-roles-sample-role/Role.noname.0.yaml diff --git a/pkg/testdata/ocm/policies/policy-disallowed-roles/policy-generator.yaml b/go/pkg/testdata/ocm/policies/policy-disallowed-roles/policy-generator.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-disallowed-roles/policy-generator.yaml rename to go/pkg/testdata/ocm/policies/policy-disallowed-roles/policy-generator.yaml diff --git a/pkg/testdata/ocm/policies/policy-high-scan/compliance-high-scan/ScanSettingBinding.high.0.yaml b/go/pkg/testdata/ocm/policies/policy-high-scan/compliance-high-scan/ScanSettingBinding.high.0.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-high-scan/compliance-high-scan/ScanSettingBinding.high.0.yaml rename to go/pkg/testdata/ocm/policies/policy-high-scan/compliance-high-scan/ScanSettingBinding.high.0.yaml diff --git a/pkg/testdata/ocm/policies/policy-high-scan/compliance-suite-high-results/ComplianceCheckResult.noname.0.yaml b/go/pkg/testdata/ocm/policies/policy-high-scan/compliance-suite-high-results/ComplianceCheckResult.noname.0.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-high-scan/compliance-suite-high-results/ComplianceCheckResult.noname.0.yaml rename to go/pkg/testdata/ocm/policies/policy-high-scan/compliance-suite-high-results/ComplianceCheckResult.noname.0.yaml diff --git a/pkg/testdata/ocm/policies/policy-high-scan/compliance-suite-high/ComplianceSuite.high.0.yaml b/go/pkg/testdata/ocm/policies/policy-high-scan/compliance-suite-high/ComplianceSuite.high.0.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-high-scan/compliance-suite-high/ComplianceSuite.high.0.yaml rename to go/pkg/testdata/ocm/policies/policy-high-scan/compliance-suite-high/ComplianceSuite.high.0.yaml diff --git a/pkg/testdata/ocm/policies/policy-high-scan/kustomization.yaml b/go/pkg/testdata/ocm/policies/policy-high-scan/kustomization.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-high-scan/kustomization.yaml rename to go/pkg/testdata/ocm/policies/policy-high-scan/kustomization.yaml diff --git a/pkg/testdata/ocm/policies/policy-high-scan/policy-generator.yaml b/go/pkg/testdata/ocm/policies/policy-high-scan/policy-generator.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-high-scan/policy-generator.yaml rename to go/pkg/testdata/ocm/policies/policy-high-scan/policy-generator.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/kustomization.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/kustomization.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/kustomization.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/kustomization.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-generator.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-generator.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-generator.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-generator.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-generaterequest.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-generaterequest.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-generaterequest.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-generaterequest.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-policies.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-policies.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-policies.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-policies.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-policyreport.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-policyreport.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-policyreport.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-policyreport.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-reports.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-reports.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-reports.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-reports.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-updaterequest.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-updaterequest.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-updaterequest.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:admin-updaterequest.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:events.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:events.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:events.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:events.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:generate.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:generate.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:generate.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:generate.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:policies.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:policies.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:policies.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:policies.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:userinfo.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:userinfo.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:userinfo.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:userinfo.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:view.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:view.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:view.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:view.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:webhook.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:webhook.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:webhook.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRole.kyverno:webhook.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRoleBinding.kyverno.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRoleBinding.kyverno.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRoleBinding.kyverno.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ClusterRoleBinding.kyverno.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ConfigMap.kyverno-metrics.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ConfigMap.kyverno-metrics.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ConfigMap.kyverno-metrics.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ConfigMap.kyverno-metrics.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ConfigMap.kyverno.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ConfigMap.kyverno.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ConfigMap.kyverno.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ConfigMap.kyverno.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.admissionreports.kyverno.io.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.admissionreports.kyverno.io.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.admissionreports.kyverno.io.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.admissionreports.kyverno.io.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.backgroundscanreports.kyverno.io.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.backgroundscanreports.kyverno.io.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.backgroundscanreports.kyverno.io.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.backgroundscanreports.kyverno.io.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusteradmissionreports.kyverno.io.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusteradmissionreports.kyverno.io.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusteradmissionreports.kyverno.io.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusteradmissionreports.kyverno.io.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterbackgroundscanreports.kyverno.io.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterbackgroundscanreports.kyverno.io.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterbackgroundscanreports.kyverno.io.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterbackgroundscanreports.kyverno.io.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterpolicies.kyverno.io.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterpolicies.kyverno.io.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterpolicies.kyverno.io.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterpolicies.kyverno.io.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterpolicyreports.wgpolicyk8s.io.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterpolicyreports.wgpolicyk8s.io.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterpolicyreports.wgpolicyk8s.io.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.clusterpolicyreports.wgpolicyk8s.io.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.generaterequests.kyverno.io.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.generaterequests.kyverno.io.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.generaterequests.kyverno.io.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.generaterequests.kyverno.io.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.policies.kyverno.io.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.policies.kyverno.io.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.policies.kyverno.io.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.policies.kyverno.io.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.policyreports.wgpolicyk8s.io.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.policyreports.wgpolicyk8s.io.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.policyreports.wgpolicyk8s.io.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.policyreports.wgpolicyk8s.io.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.updaterequests.kyverno.io.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.updaterequests.kyverno.io.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.updaterequests.kyverno.io.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/CustomResourceDefinition.updaterequests.kyverno.io.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Deployment.kyverno.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Deployment.kyverno.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Deployment.kyverno.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Deployment.kyverno.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Namespace.kyverno.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Namespace.kyverno.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Namespace.kyverno.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Namespace.kyverno.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Role.kyverno:leaderelection.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Role.kyverno:leaderelection.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Role.kyverno:leaderelection.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Role.kyverno:leaderelection.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/RoleBinding.kyverno:leaderelection.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/RoleBinding.kyverno:leaderelection.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/RoleBinding.kyverno:leaderelection.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/RoleBinding.kyverno:leaderelection.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Service.kyverno-svc-metrics.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Service.kyverno-svc-metrics.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Service.kyverno-svc-metrics.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Service.kyverno-svc-metrics.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Service.kyverno-svc.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Service.kyverno-svc.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Service.kyverno-svc.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/Service.kyverno-svc.yaml diff --git a/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ServiceAccount.kyverno.yaml b/go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ServiceAccount.kyverno.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ServiceAccount.kyverno.yaml rename to go/pkg/testdata/ocm/policies/policy-install-kyverno-from-manifests/policy-install-kyverno-from-manifests/ServiceAccount.kyverno.yaml diff --git a/pkg/testdata/ocm/policies/policy-kyverno-require-labels/check-kyverno-reports/require-lables.yaml b/go/pkg/testdata/ocm/policies/policy-kyverno-require-labels/check-kyverno-reports/require-lables.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-kyverno-require-labels/check-kyverno-reports/require-lables.yaml rename to go/pkg/testdata/ocm/policies/policy-kyverno-require-labels/check-kyverno-reports/require-lables.yaml diff --git a/pkg/testdata/ocm/policies/policy-kyverno-require-labels/kustomization.yaml b/go/pkg/testdata/ocm/policies/policy-kyverno-require-labels/kustomization.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-kyverno-require-labels/kustomization.yaml rename to go/pkg/testdata/ocm/policies/policy-kyverno-require-labels/kustomization.yaml diff --git a/pkg/testdata/ocm/policies/policy-kyverno-require-labels/policy-generator.yaml b/go/pkg/testdata/ocm/policies/policy-kyverno-require-labels/policy-generator.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-kyverno-require-labels/policy-generator.yaml rename to go/pkg/testdata/ocm/policies/policy-kyverno-require-labels/policy-generator.yaml diff --git a/pkg/testdata/ocm/policies/policy-kyverno-require-labels/policy-kyverno-require-labels/ClusterPolicy.require-labels.0.yaml b/go/pkg/testdata/ocm/policies/policy-kyverno-require-labels/policy-kyverno-require-labels/ClusterPolicy.require-labels.0.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-kyverno-require-labels/policy-kyverno-require-labels/ClusterPolicy.require-labels.0.yaml rename to go/pkg/testdata/ocm/policies/policy-kyverno-require-labels/policy-kyverno-require-labels/ClusterPolicy.require-labels.0.yaml diff --git a/pkg/testdata/ocm/policies/policy-nginx-deployment/kustomization.yaml b/go/pkg/testdata/ocm/policies/policy-nginx-deployment/kustomization.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-nginx-deployment/kustomization.yaml rename to go/pkg/testdata/ocm/policies/policy-nginx-deployment/kustomization.yaml diff --git a/pkg/testdata/ocm/policies/policy-nginx-deployment/policy-generator.yaml b/go/pkg/testdata/ocm/policies/policy-nginx-deployment/policy-generator.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-nginx-deployment/policy-generator.yaml rename to go/pkg/testdata/ocm/policies/policy-nginx-deployment/policy-generator.yaml diff --git a/pkg/testdata/ocm/policies/policy-nginx-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml b/go/pkg/testdata/ocm/policies/policy-nginx-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml similarity index 100% rename from pkg/testdata/ocm/policies/policy-nginx-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml rename to go/pkg/testdata/ocm/policies/policy-nginx-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml diff --git a/pkg/testdata/ocm/policy-results/placementdecisions.cluster.open-cluster-management.io.yaml b/go/pkg/testdata/ocm/policy-results/placementdecisions.cluster.open-cluster-management.io.yaml similarity index 100% rename from pkg/testdata/ocm/policy-results/placementdecisions.cluster.open-cluster-management.io.yaml rename to go/pkg/testdata/ocm/policy-results/placementdecisions.cluster.open-cluster-management.io.yaml diff --git a/pkg/testdata/ocm/policy-results/policies.policy.open-cluster-management.io.yaml b/go/pkg/testdata/ocm/policy-results/policies.policy.open-cluster-management.io.yaml similarity index 100% rename from pkg/testdata/ocm/policy-results/policies.policy.open-cluster-management.io.yaml rename to go/pkg/testdata/ocm/policy-results/policies.policy.open-cluster-management.io.yaml diff --git a/pkg/testdata/ocm/policy-results/policysets.policy.open-cluster-management.io.yaml b/go/pkg/testdata/ocm/policy-results/policysets.policy.open-cluster-management.io.yaml similarity index 100% rename from pkg/testdata/ocm/policy-results/policysets.policy.open-cluster-management.io.yaml rename to go/pkg/testdata/ocm/policy-results/policysets.policy.open-cluster-management.io.yaml diff --git a/pkg/testdata/ocm/profile.json b/go/pkg/testdata/ocm/profile.json similarity index 100% rename from pkg/testdata/ocm/profile.json rename to go/pkg/testdata/ocm/profile.json diff --git a/pkg/testdata/oscal/catalog.json b/go/pkg/testdata/oscal/catalog.json similarity index 100% rename from pkg/testdata/oscal/catalog.json rename to go/pkg/testdata/oscal/catalog.json diff --git a/pkg/testdata/oscal/profile.json b/go/pkg/testdata/oscal/profile.json similarity index 100% rename from pkg/testdata/oscal/profile.json rename to go/pkg/testdata/oscal/profile.json diff --git a/pkg/types/c2pcr/c2pcr_type.go b/go/pkg/types/c2pcr/c2pcr_type.go similarity index 100% rename from pkg/types/c2pcr/c2pcr_type.go rename to go/pkg/types/c2pcr/c2pcr_type.go diff --git a/pkg/types/c2pcr/c2pcrparsed_type.go b/go/pkg/types/c2pcr/c2pcrparsed_type.go similarity index 79% rename from pkg/types/c2pcr/c2pcrparsed_type.go rename to go/pkg/types/c2pcr/c2pcrparsed_type.go index fed5385..885c6d8 100644 --- a/pkg/types/c2pcr/c2pcrparsed_type.go +++ b/go/pkg/types/c2pcr/c2pcrparsed_type.go @@ -17,9 +17,9 @@ limitations under the License. package c2pcr import ( - "github.com/IBM/compliance-to-policy/pkg/oscal" - typesoscal "github.com/IBM/compliance-to-policy/pkg/types/oscal" - typecd "github.com/IBM/compliance-to-policy/pkg/types/oscal/componentdefinition" + "github.com/oscal-compass/compliance-to-policy/go/pkg/oscal" + typesoscal "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal" + typecd "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/componentdefinition" ) type C2PCRParsed struct { diff --git a/pkg/types/configurationpolicy/configurationpolicy_types.go b/go/pkg/types/configurationpolicy/configurationpolicy_types.go similarity index 100% rename from pkg/types/configurationpolicy/configurationpolicy_types.go rename to go/pkg/types/configurationpolicy/configurationpolicy_types.go diff --git a/pkg/types/internalcompliance/compliance_type.go b/go/pkg/types/internalcompliance/compliance_type.go similarity index 100% rename from pkg/types/internalcompliance/compliance_type.go rename to go/pkg/types/internalcompliance/compliance_type.go diff --git a/pkg/types/oscal/assessmentresults/assessmentresult_types.go b/go/pkg/types/oscal/assessmentresults/assessmentresult_types.go similarity index 98% rename from pkg/types/oscal/assessmentresults/assessmentresult_types.go rename to go/pkg/types/oscal/assessmentresults/assessmentresult_types.go index 0496f0a..2572a66 100644 --- a/pkg/types/oscal/assessmentresults/assessmentresult_types.go +++ b/go/pkg/types/oscal/assessmentresults/assessmentresult_types.go @@ -19,7 +19,7 @@ package assessmentresults import ( "time" - "github.com/IBM/compliance-to-policy/pkg/types/oscal/common" + "github.com/oscal-compass/compliance-to-policy/go/pkg/types/oscal/common" ) type Metadata struct { diff --git a/pkg/types/oscal/catalog_types.go b/go/pkg/types/oscal/catalog_types.go similarity index 100% rename from pkg/types/oscal/catalog_types.go rename to go/pkg/types/oscal/catalog_types.go diff --git a/pkg/types/oscal/common/common_types.go b/go/pkg/types/oscal/common/common_types.go similarity index 100% rename from pkg/types/oscal/common/common_types.go rename to go/pkg/types/oscal/common/common_types.go diff --git a/pkg/types/oscal/componentdefinition/component-definition.template.json b/go/pkg/types/oscal/componentdefinition/component-definition.template.json similarity index 100% rename from pkg/types/oscal/componentdefinition/component-definition.template.json rename to go/pkg/types/oscal/componentdefinition/component-definition.template.json diff --git a/pkg/types/oscal/componentdefinition/componentdefinition_types.go b/go/pkg/types/oscal/componentdefinition/componentdefinition_types.go similarity index 100% rename from pkg/types/oscal/componentdefinition/componentdefinition_types.go rename to go/pkg/types/oscal/componentdefinition/componentdefinition_types.go diff --git a/pkg/types/oscal/profile_types.go b/go/pkg/types/oscal/profile_types.go similarity index 100% rename from pkg/types/oscal/profile_types.go rename to go/pkg/types/oscal/profile_types.go diff --git a/pkg/types/placementdecision/helper.go b/go/pkg/types/placementdecision/helper.go similarity index 100% rename from pkg/types/placementdecision/helper.go rename to go/pkg/types/placementdecision/helper.go diff --git a/pkg/types/placementdecision/placementdecision_types.go b/go/pkg/types/placementdecision/placementdecision_types.go similarity index 100% rename from pkg/types/placementdecision/placementdecision_types.go rename to go/pkg/types/placementdecision/placementdecision_types.go diff --git a/pkg/types/placements/placementbinding_types.go b/go/pkg/types/placements/placementbinding_types.go similarity index 100% rename from pkg/types/placements/placementbinding_types.go rename to go/pkg/types/placements/placementbinding_types.go diff --git a/pkg/types/placements/placementrule_types.go b/go/pkg/types/placements/placementrule_types.go similarity index 100% rename from pkg/types/placements/placementrule_types.go rename to go/pkg/types/placements/placementrule_types.go diff --git a/pkg/types/policy/helper.go b/go/pkg/types/policy/helper.go similarity index 100% rename from pkg/types/policy/helper.go rename to go/pkg/types/policy/helper.go diff --git a/pkg/types/policy/policy_types.go b/go/pkg/types/policy/policy_types.go similarity index 100% rename from pkg/types/policy/policy_types.go rename to go/pkg/types/policy/policy_types.go diff --git a/pkg/types/policy/policyset_types.go b/go/pkg/types/policy/policyset_types.go similarity index 100% rename from pkg/types/policy/policyset_types.go rename to go/pkg/types/policy/policyset_types.go diff --git a/pkg/types/policycomposition/policycomposition_type.go b/go/pkg/types/policycomposition/policycomposition_type.go similarity index 100% rename from pkg/types/policycomposition/policycomposition_type.go rename to go/pkg/types/policycomposition/policycomposition_type.go diff --git a/pkg/types/policygenerator/policygenerator_type.go b/go/pkg/types/policygenerator/policygenerator_type.go similarity index 100% rename from pkg/types/policygenerator/policygenerator_type.go rename to go/pkg/types/policygenerator/policygenerator_type.go diff --git a/pkg/types/report/report_type.go b/go/pkg/types/report/report_type.go similarity index 100% rename from pkg/types/report/report_type.go rename to go/pkg/types/report/report_type.go diff --git a/pkg/types/utils/utils.go b/go/pkg/types/utils/utils.go similarity index 100% rename from pkg/types/utils/utils.go rename to go/pkg/types/utils/utils.go diff --git a/pkg/utils.go b/go/pkg/utils.go similarity index 100% rename from pkg/utils.go rename to go/pkg/utils.go diff --git a/scripts/README.md b/go/scripts/README.md similarity index 100% rename from scripts/README.md rename to go/scripts/README.md diff --git a/scripts/cleanup-argocd.sh b/go/scripts/cleanup-argocd.sh similarity index 100% rename from scripts/cleanup-argocd.sh rename to go/scripts/cleanup-argocd.sh diff --git a/scripts/collect/cronjob.yaml b/go/scripts/collect/cronjob.yaml similarity index 100% rename from scripts/collect/cronjob.yaml rename to go/scripts/collect/cronjob.yaml diff --git a/scripts/collect/rbac.yaml b/go/scripts/collect/rbac.yaml similarity index 100% rename from scripts/collect/rbac.yaml rename to go/scripts/collect/rbac.yaml diff --git a/scripts/docker/Dockerfile b/go/scripts/docker/Dockerfile similarity index 100% rename from scripts/docker/Dockerfile rename to go/scripts/docker/Dockerfile diff --git a/scripts/docker/install-kubectl.sh b/go/scripts/docker/install-kubectl.sh similarity index 100% rename from scripts/docker/install-kubectl.sh rename to go/scripts/docker/install-kubectl.sh diff --git a/scripts/gitops/acm-webhook.yaml b/go/scripts/gitops/acm-webhook.yaml similarity index 100% rename from scripts/gitops/acm-webhook.yaml rename to go/scripts/gitops/acm-webhook.yaml diff --git a/scripts/gitops/channel.yaml b/go/scripts/gitops/channel.yaml similarity index 100% rename from scripts/gitops/channel.yaml rename to go/scripts/gitops/channel.yaml diff --git a/scripts/gitops/subscription-admin.yaml b/go/scripts/gitops/subscription-admin.yaml similarity index 100% rename from scripts/gitops/subscription-admin.yaml rename to go/scripts/gitops/subscription-admin.yaml diff --git a/scripts/gitops/subscription.yaml b/go/scripts/gitops/subscription.yaml similarity index 100% rename from scripts/gitops/subscription.yaml rename to go/scripts/gitops/subscription.yaml diff --git a/scripts/init.sh b/go/scripts/init.sh similarity index 100% rename from scripts/init.sh rename to go/scripts/init.sh diff --git a/scripts/install-argocd.sh b/go/scripts/install-argocd.sh similarity index 100% rename from scripts/install-argocd.sh rename to go/scripts/install-argocd.sh diff --git a/scripts/kyverno/README.md b/go/scripts/kyverno/README.md similarity index 100% rename from scripts/kyverno/README.md rename to go/scripts/kyverno/README.md diff --git a/scripts/kyverno/collect/cronjob.yaml b/go/scripts/kyverno/collect/cronjob.yaml similarity index 100% rename from scripts/kyverno/collect/cronjob.yaml rename to go/scripts/kyverno/collect/cronjob.yaml diff --git a/scripts/kyverno/collect/rbac.yaml b/go/scripts/kyverno/collect/rbac.yaml similarity index 100% rename from scripts/kyverno/collect/rbac.yaml rename to go/scripts/kyverno/collect/rbac.yaml diff --git a/scripts/pod.yaml b/go/scripts/pod.yaml similarity index 100% rename from scripts/pod.yaml rename to go/scripts/pod.yaml diff --git a/scripts/setup-argocd.sh b/go/scripts/setup-argocd.sh similarity index 100% rename from scripts/setup-argocd.sh rename to go/scripts/setup-argocd.sh diff --git a/scripts/uninstall-argocd.sh b/go/scripts/uninstall-argocd.sh similarity index 100% rename from scripts/uninstall-argocd.sh rename to go/scripts/uninstall-argocd.sh diff --git a/plugins_public/plugins/__init__.py b/plugins_public/plugins/__init__.py new file mode 100644 index 0000000..bd26775 --- /dev/null +++ b/plugins_public/plugins/__init__.py @@ -0,0 +1,15 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/plugins_public/plugins/kyverno.py b/plugins_public/plugins/kyverno.py new file mode 100644 index 0000000..ba12598 --- /dev/null +++ b/plugins_public/plugins/kyverno.py @@ -0,0 +1,153 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pathlib +import shutil +from datetime import datetime, timezone +from typing import Any, Dict, List, Optional + +import yaml +from jinja2 import Template +from pydantic import Field + +from c2p.common.err import C2PError +from c2p.common.logging import getLogger +from c2p.common.utils import get_datetime, get_dict_safely +from c2p.framework.models import Policy, PVPResult, RawResult +from c2p.framework.models.pvp_result import ( + ObservationByCheck, + PVPResult, + ResultEnum, + Subject, +) +from c2p.framework.plugin_spec import PluginConfig, PluginSpec + +logger = getLogger(__name__) + +status_dictionary = { + 'pass': ResultEnum.Pass, + 'fail': ResultEnum.Failure, + 'warn': ResultEnum.Failure, + 'skip': ResultEnum.Error, + 'error': ResultEnum.Error, +} + + +class PluginConfigKyverno(PluginConfig): + policy_template_dir: str = Field(..., title='Path to Policy template directory') + deliverable_policy_dir: str = Field(..., title='Path to deliverable (generated) policy directory') + + +class PluginKyverno(PluginSpec): + + def __init__(self, config: Optional[PluginConfigKyverno] = None) -> None: + super().__init__() + self.config = config + + def generate_pvp_result(self, raw_result: RawResult) -> PVPResult: + pvp_result: PVPResult = PVPResult() + observations: List[ObservationByCheck] = [] + + polrs = list( + filter( + lambda x: x['apiVersion'] == 'wgpolicyk8s.io/v1alpha2' and x['kind'] == 'PolicyReport', raw_result.data + ) + ) + cpolrs = list( + filter( + lambda x: x['apiVersion'] == 'wgpolicyk8s.io/v1alpha2' and x['kind'] == 'ClusterPolicyReport', + raw_result.data, + ) + ) + + results = [] + for polr in polrs: + for result in polr['results']: + results.append(result) + for cpolr in cpolrs: + for result in cpolr['results']: + results.append(result) + + policy_names = list(map(lambda x: x['policy'], results)) # policy_name is used as check_id + policy_names = set(policy_names) + + for policy_name in policy_names: + observation = ObservationByCheck(check_id=policy_name, methods=['AUTOMATED'], collected=get_datetime()) + + results_per_policy = filter(lambda x: x['policy'] == policy_name, results) + subjects = [] + for rpp in results_per_policy: + result = rpp['result'] + result = status_dictionary[result] if result in status_dictionary else ResultEnum.Error + timestamp = get_dict_safely(rpp, ['timestamp', 'seconds'], get_datetime().second) + evaluated_on = datetime.fromtimestamp(timestamp, tz=timezone.utc) + message = rpp['message'] + + def to_subject(resource): + kind = get_dict_safely(resource, 'kind') + api_version = get_dict_safely(resource, 'apiVersion', '') + name = get_dict_safely(resource, 'name') + namespace = get_dict_safely(resource, 'namespace', '(ClusterScope)') + uid = get_dict_safely(resource, 'uid') + return Subject( + title=f'{api_version}/{kind} {name} {namespace}', + type='resource', + result=result, + resource_id=uid, + evaluated_on=evaluated_on, + reason=message, + ) + + subjects = subjects + list(map(to_subject, get_dict_safely(rpp, 'resources'))) + + observation.subjects = subjects + observations.append(observation) + + pvp_result.observations_by_check = observations + return pvp_result + + def generate_pvp_policy(self, policy: Policy): + rule_sets = policy.rule_sets + parameters = policy.parameters + policy_template_dir = self.config.policy_template_dir + deliverable_policy_dir = self.config.deliverable_policy_dir + if not pathlib.Path(deliverable_policy_dir).exists(): + logger.info(f"The deliverable policy directory '{deliverable_policy_dir}' is not found. Creating...") + pathlib.Path(deliverable_policy_dir).mkdir(parents=True) + else: + if not pathlib.Path(deliverable_policy_dir).is_dir(): + raise C2PError(f"The deliverable policy directory '{deliverable_policy_dir}' is not directory.") + for rule_set in rule_sets: + each_policy_template_dir = pathlib.Path(f'{policy_template_dir}/{rule_set.rule_id}') + each_deliverable_policy_dir = pathlib.Path(f'{deliverable_policy_dir}/{rule_set.rule_id}') + shutil.copytree(each_policy_template_dir, each_deliverable_policy_dir, dirs_exist_ok=True) + contents = each_deliverable_policy_dir.glob('**/*') + for path in list(contents): + tp_str = path.open('r').read() + yamldocs = yaml.safe_load_all(path.open('r')) + if not self.__is_policy_file(yamldocs): + tp = Template(source=tp_str) + kv = dict(map(lambda x: (x.id, x.value), parameters)) + rendered = tp.render(kv) + path.write_text(rendered) + + def __is_policy_file(self, yamldocs: List[Dict[str, Any]]) -> bool: + for yamldoc in yamldocs: + kind = get_dict_safely(yamldoc, 'kind', None) + api_version = get_dict_safely(yamldoc, 'apiVersion', None) + if kind in ['ClusterPolicy', 'Policy'] and api_version == 'kyverno.io/v1': + return True + return False diff --git a/plugins_public/plugins/ocm.py b/plugins_public/plugins/ocm.py new file mode 100644 index 0000000..7c1c068 --- /dev/null +++ b/plugins_public/plugins/ocm.py @@ -0,0 +1,294 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import pathlib +import shutil +from datetime import datetime +from typing import Any, Dict, List, Optional, TypeVar + +import yaml +from pydantic import BaseModel, Field + +from c2p.common.err import C2PError +from c2p.common.logging import getLogger +from c2p.common.utils import get_datetime, get_dict_safely, remove_none +from c2p.framework.models import Policy, PVPResult, RawResult +from c2p.framework.models.pvp_result import ( + ObservationByCheck, + PVPResult, + ResultEnum, + Subject, +) +from c2p.framework.plugin_spec import PluginConfig, PluginSpec + +logger = getLogger(__name__) + +status_dictionary = { + 'Compliant': ResultEnum.Pass, + 'NonCompliant': ResultEnum.Failure, +} + +ANNOTATION_COMPONENT_TITLE = "compliance-to-policy.component-title" + + +class Manifest(BaseModel): + remediationAction: Optional[str] = None + severity: Optional[str] = None + complianceType: Optional[str] = None + metadataComplianceType: Optional[str] = None + evaluationInterval: Optional[Dict[str, Any]] = None + namespaceSelector: Optional[Dict[str, Any]] = None + pruneObjectBehavior: Optional[str] = None + patches: Optional[Dict[str, Any]] = None + path: Optional[str] = None + extraDependencies: Optional[List[Dict[str, str]]] = None + ignorePending: Optional[bool] = False + + +class PolicyConfig(BaseModel): + name: str + manifests: Optional[List[Manifest]] = [] + standards: Optional[List[str]] = [] + controls: Optional[List[str]] = [] + categories: Optional[List[str]] = [] + consolidateManifests: Optional[bool] = True + orderManifests: Optional[bool] = False + informGatekeeperPolicies: Optional[bool] = False + informKyvernoPolicies: Optional[bool] = False + remediationAction: Optional[str] = 'inform' + severity: Optional[str] = 'high' + complianceType: Optional[str] = 'mustnothave' + + +class PluginConfigOCM(PluginConfig): + policy_template_dir: str = Field(..., title='Path to Policy template directory') + deliverable_policy_dir: str = Field(..., title='Path to deliverable (generated) policy directory') + namespace: str = Field(..., title='Namespace in OCM Hub to which policies are delivered') + paremeters_configmap_name: str = Field('c2p-parameters', title='Name of configmap for parameters') + cluster_selectors: Dict[str, str] = Field( + ..., title='Pair of cluster label name and value to which policies are distributed to matched clusters' + ) + policy_set_name: str = 'test' + exclude_namespaces: List[str] = Field( + [ + 'kube-system', + 'open-cluster-management', + 'open-cluster-management-agent', + 'open-cluster-management-agent-addon', + ], + title='Namespaces that policy is not applied', + ) + include_namespaces: List[str] = Field(['*'], title='Namespaces that policy must be applied') + + +class PluginOCM(PluginSpec): + + def __init__(self, config: Optional[PluginConfigOCM] = None) -> None: + super().__init__() + self.config = config + + def generate_pvp_result(self, raw_result: RawResult) -> PVPResult: + pvp_result: PVPResult = PVPResult() + observations: List[ObservationByCheck] = [] + + policies = list( + filter( + lambda x: x['apiVersion'] == 'policy.open-cluster-management.io/v1' and x['kind'] == 'Policy', + raw_result.data, + ) + ) + + # Root policy resource on Hub + root_policies = list( + filter( + lambda x: get_dict_safely(x, ['metadata', 'labels', 'policy.open-cluster-management.io/cluster-name']) + == None, + policies, + ) + ) + + # Policy resources of each cluster to which the root policies are delivered + each_policies = list( + filter( + lambda x: get_dict_safely(x, ['metadata', 'labels', 'policy.open-cluster-management.io/cluster-name']) + != None, + policies, + ) + ) + + # policy_name is used as check_id + policy_namespace_names = list(map(lambda x: (x['metadata']['name'], x['metadata']['namespace']), root_policies)) + + for policy_name, root_namespace in policy_namespace_names: + observation = ObservationByCheck(check_id=policy_name, methods=['AUTOMATED'], collected=get_datetime()) + + results_per_policy = filter( + lambda x: x['metadata']['name'] == f'{root_namespace}.{policy_name}', each_policies + ) + subjects = [] + for rpp in results_per_policy: + name = get_dict_safely(rpp, ['metadata', 'name']) + cluster_name = get_dict_safely(rpp, ['metadata', 'namespace']) + result = get_dict_safely(rpp, ['status', 'compliant']) + result = status_dictionary[result] if result in status_dictionary else ResultEnum.Error + details = get_dict_safely(rpp, ['status', 'details']) + if isinstance(details, list) and len(details) > 0: + for detail in details: + history = detail['history'] + if isinstance(history, list) and len(history) > 0: + latest_history = history[0] + event_name = latest_history['eventName'] + last_timestamp = latest_history['lastTimestamp'] + message = latest_history['message'] + else: + logger.warn(f'"details" are not found for name "{name}" for "{cluster_name}"') + + evaluated_on = ( + datetime.fromisoformat(last_timestamp.replace('Z', '+00:00')) + if last_timestamp != None + else get_datetime() + ) + + event_name = event_name if event_name != None else '' + message = message if message != None else '' + reason = f'[{event_name}] {message}' if event_name != '' and message != '' else None + subject = Subject( + title=f'Cluster "{cluster_name}"', + type='cluster', + result=result, + resource_id=cluster_name, + evaluated_on=evaluated_on, + reason=reason, + ) + subjects.append(subject) + + observation.subjects = subjects + observations.append(observation) + + pvp_result.observations_by_check = observations + return pvp_result + + def generate_pvp_policy(self, policy: Policy): + rule_sets = policy.rule_sets + parameters = policy.parameters + policy_template_dir = pathlib.Path(self.config.policy_template_dir) + deliverable_policy_dir = pathlib.Path(self.config.deliverable_policy_dir) + if not deliverable_policy_dir.exists(): + logger.info( + f"The deliverable policy directory '{deliverable_policy_dir.as_posix()}' is not found. Creating..." + ) + deliverable_policy_dir.mkdir(parents=True) + else: + if not deliverable_policy_dir.is_dir(): + raise C2PError( + f"The deliverable policy directory '{deliverable_policy_dir.as_posix()}' is not directory." + ) + policy_config_map: Dict[str, PolicyConfig] = {} + for rule_set in rule_sets: + policy_id = rule_set.rule_id + each_policy_template_dir = policy_template_dir / policy_id + each_deliverable_policy_dir = deliverable_policy_dir / policy_id + shutil.copytree(each_policy_template_dir, each_deliverable_policy_dir, dirs_exist_ok=True) + standards = [] + controls = [] + categories = [] + policy_generator_path = each_deliverable_policy_dir / 'policy-generator.yaml' + policy_generator = yaml.safe_load(policy_generator_path.open('r')) + policy_generator['policyDefaults']['namespace'] = self.config.namespace + policy_generator['policyDefaults']['standards'] = standards + policy_generator['policyDefaults']['controls'] = controls + policy_generator['policyDefaults']['categories'] = categories + policy_generator['policyDefaults']['placement'] = {'clusterSelectors': self.config.cluster_selectors} + yaml.safe_dump(policy_generator, policy_generator_path.open('w')) + + pg_policy = policy_generator['policies'][0] + if policy_id in policy_config_map: + policy_config = policy_config_map[policy_id] + else: + policy_config = PolicyConfig.parse_obj(pg_policy) + for idx, m in enumerate(policy_config.manifests): + policy_config.manifests[idx].path = m.path.replace('./', f'./{policy_id}/') + policy_config.standards = self.__merge_uniquely(policy_config.standards, standards) + policy_config.categories = self.__merge_uniquely(policy_config.controls, categories) + policy_config.controls = self.__merge_uniquely(policy_config.categories, controls) + policy_config_map[policy_id] = policy_config + + policy_set_name_sanitized = self.config.policy_set_name.lower().replace(' ', '-') # DNS Compliant value + policy_set = { + 'name': policy_set_name_sanitized, + 'policies': list(policy_config_map.keys()), + } + + policy_set_generator = { + 'apiVersion': 'policy.open-cluster-management.io/v1', + 'kind': 'PolicyGenerator', + 'metadata': {'name': 'policy-set'}, + 'placementBindingDefaults': {'name': 'policy-set'}, + 'policyDefaults': { + 'placement': {'labelSelector': self.config.cluster_selectors}, + 'consolidateManifests': False, + 'orderManifests': False, + 'informGatekeeperPolicies': False, + 'informKyvernoPolicies': False, + 'namespaceSelector': { + 'exclude': self.config.exclude_namespaces, + 'include': self.config.include_namespaces, + }, + 'namespace': self.config.namespace, + }, + 'policySetDefaults': {'placement': {'labelSelector': self.config.cluster_selectors}}, + 'policies': list(map(lambda x: x.dict(), policy_config_map.values())), + 'policySets': [policy_set], + } + + parameters_configmap = { + 'apiVersion': 'v1', + 'kind': 'ConfigMap', + 'metadata': {'name': self.config.paremeters_configmap_name, 'namespace': self.config.namespace}, + 'data': dict(map(lambda x: (x.id, x.value), parameters)), + } + + kustomize_patch = { + 'target': {'kind': 'PolicySet', 'name': policy_set_name_sanitized}, + 'patch': json.dumps( + [ + { + 'op': 'replace', + 'path': f'/metadata/annotations/{ANNOTATION_COMPONENT_TITLE}', + 'value': self.config.policy_set_name, + } + ] + ), + } + + kustomize = { + 'generators': ['./policy-generator.yaml'], + 'patches': [kustomize_patch], + 'resources': ['./parameters.yaml'], + } + + yaml.safe_dump(remove_none(policy_set_generator), (deliverable_policy_dir / 'policy-generator.yaml').open('w')) + yaml.safe_dump(parameters_configmap, (deliverable_policy_dir / 'parameters.yaml').open('w')) + yaml.safe_dump(kustomize, (deliverable_policy_dir / 'kustomization.yaml').open('w')) + + T = TypeVar('T') + + def __merge_uniquely(self, targets: Optional[List[T]], value: List[T]) -> List[T]: + x = set(targets) if targets != None else set() + for _ in value: + x.add(value) + return list(set(x)) diff --git a/plugins_public/tests/__init__.py b/plugins_public/tests/__init__.py new file mode 100644 index 0000000..bd26775 --- /dev/null +++ b/plugins_public/tests/__init__.py @@ -0,0 +1,15 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/plugins_public/tests/data/kyverno/clusterpolicyreports.wgpolicyk8s.io.yaml b/plugins_public/tests/data/kyverno/clusterpolicyreports.wgpolicyk8s.io.yaml new file mode 100644 index 0000000..ded9522 --- /dev/null +++ b/plugins_public/tests/data/kyverno/clusterpolicyreports.wgpolicyk8s.io.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +items: [] +kind: List +metadata: + resourceVersion: "" diff --git a/plugins_public/tests/data/kyverno/component-definition.csv b/plugins_public/tests/data/kyverno/component-definition.csv new file mode 100644 index 0000000..ea37134 --- /dev/null +++ b/plugins_public/tests/data/kyverno/component-definition.csv @@ -0,0 +1,6 @@ +$$Component_Title,$$Component_Description,$$Component_Type,$$Control_Id_List,$$Rule_Id,$$Rule_Description,$Parameter_Id,$Parameter_Description,$Parameter_Value_Alternatives,$Parameter_Value_Default,$$Profile_Source,$$Profile_Description,Rule_Actual_State_Data_Request_Evidence_Format_Reference_URL_list,Rule_Actual_State_TimeToLive,$Check_Id,$Check_Description,Fetcher_id,Fetcher_Description,Fix_id,Fix_Description,Rule_implementation_status,Rule_POAM_Reference_URL,$$Namespace +A human readable name for the component.,A description of the component including information about its function.,A category describing the purpose of the component. ALLOWED VALUES interconnection:software:hardware:service:physical:process-procedure:plan:guidance:standard:validation:,A list of textual labels that uniquely identify the controls or statements that the component implements.,A textual label that uniquely identifies a policy (desired state) that can be used to reference it elsewhere in this or other documents.,A description of the policy (desired state) including information about its purpose and scope.,A textual label that uniquely identifies the parameter associated with that policy (desired state) or controls implemented by the policy (desired state).,A description of the parameter including the purpose and use of the parameter.,ONLY for the policy (desired state) parameters: A value or set of values the parameter can take. The catalog parameters values are defined in the catalog. ,"A value recommended by Compliance Team in this profile for the parameter of the control or policy (desired state). If a CIS-benchmark exists, the default default could be the CIS-benchmark recommanded value.",A URL reference to the source catalog or profile for which this component is implementing controls for. A profile designates a selection and configuration of controls from one or more catalogs,A description of the profile.,A list of URL references that contain the Actual State Data Model (eg schema or swager API or procedure template or terraform schema). Needed by the fetcher developer. ,A TimeToLive value of the duration of time the actual state is valid before it becomes stale or obsolite or overriden. Needed by the fetcher developer. ,A textual label that uniquely identifies a check of the policy (desired state) that can be used to reference it elsewhere in this or other documents.,A description of the check of the policy (desired state) including the method (interview or examine or test) and procedure details.,A textual label that uniquely identifies a collector of the actual state (evidence) associated with the policy (desired state) that can be used to reference it elsewhere in this or other documents.,A description of the collector of the actual state (evidence) associated with the policy (desired state) including the method (interview or examine or API) and questionaire or API details.,A textual label that uniquely identifies the fix of the failed policy.,A description of the fix to remediate the failed policy.,Indicates the degree to which the a given policy is implemented. ALLOWED VALUES: IMPLEMENTED: The control is fully implemented. PARTIAL: The control is partially implemented. PLANNED: There is a plan for implementing the control as explained in the remarks. ALTERNATIVE: There is an alternative implementation for this control as explained in the remarks. NOT-APPLICABLE: This control does not apply to this system as justified in the remarks.,A URL reference to the Plan of Action and Milestones this component may be subjected to for remediation or deviation or mitigation in case of the policy (desired state) non compliance or error or failure. ,"A namespace qualifying the property's name. This allows different organizations to associate distinct semantics with the same name. Used in conjunction with ""class"" as the ontology concept. " +Managed Kubernetes,Managed Kubernetes cluster,Service,cm-2,allowed-base-images,"Building images which specify a base as their origin is a good start to improving supply chain security, but over time organizations may want to build an allow list of specific base images which are allowed to be used when constructing containers. This policy ensures that a container's base, found in an OCI annotation, is in a cluster-wide allow list.",allowed_baseimages,Allowed baseimages,gcr.io/distroless/static:root,gcr.io/distroless/static:root,https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json,NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE,,,allowed-base-images,"Building images which specify a base as their origin is a good start to improving supply chain security, but over time organizations may want to build an allow list of specific base images which are allowed to be used when constructing containers. This policy ensures that a container's base, found in an OCI annotation, is in a cluster-wide allow list.",,,,,,,http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud +Managed Kubernetes,Managed Kubernetes cluster,Service,cm-2.1,disallow-capabilities,"Images coming from certain registries require authentication in order to pull them, and the kubelet uses this information in the form of an imagePullSecret to pull those images on behalf of your Pod. This policy searches for images coming from a registry called `corp.reg.com` and, if found, will mutate the Pod to add an IimagePullSecret called `my-secret`.",,,,,https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json,NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE,,,disallow-capabilities,Adding capabilities beyond those listed in the policy must be disallowed.,,,,,,,http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud +Kyverno,Kyverno as Policy Validation Point,Validation,na,allowed-base-images,"Building images which specify a base as their origin is a good start to improving supply chain security, but over time organizations may want to build an allow list of specific base images which are allowed to be used when constructing containers. This policy ensures that a container's base, found in an OCI annotation, is in a cluster-wide allow list.",,,,,https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json,NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE,,,allowed-base-images,"Building images which specify a base as their origin is a good start to improving supply chain security, but over time organizations may want to build an allow list of specific base images which are allowed to be used when constructing containers. This policy ensures that a container's base, found in an OCI annotation, is in a cluster-wide allow list.",,,,,,,http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud +Kyverno,Kyverno as Policy Validation Point,Validation,na,disallow-capabilities,"Images coming from certain registries require authentication in order to pull them, and the kubelet uses this information in the form of an imagePullSecret to pull those images on behalf of your Pod. This policy searches for images coming from a registry called `corp.reg.com` and, if found, will mutate the Pod to add an IimagePullSecret called `my-secret`.",,,,,https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json,NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE,,,disallow-capabilities,Adding capabilities beyond those listed in the policy must be disallowed.,,,,,,,http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud \ No newline at end of file diff --git a/plugins_public/tests/data/kyverno/component-definition.json b/plugins_public/tests/data/kyverno/component-definition.json new file mode 100644 index 0000000..5aa060f --- /dev/null +++ b/plugins_public/tests/data/kyverno/component-definition.json @@ -0,0 +1,210 @@ +{ + "component-definition": { + "uuid": "a41933c9-2710-4492-9010-aadc1c602157", + "metadata": { + "title": "Component Definition for Kube", + "last-modified": "2024-04-14T07:18:19+00:00", + "version": "1.0", + "oscal-version": "1.0.4" + }, + "components": [ + { + "uuid": "b4087407-521b-4763-aebc-3a0099870d37", + "type": "Service", + "title": "Managed Kubernetes", + "description": "Managed Kubernetes cluster", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "allowed-base-images", + "remarks": "rule_set_0" + }, + { + "name": "Rule_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Building images which specify a base as their origin is a good start to improving supply chain security, but over time organizations may want to build an allow list of specific base images which are allowed to be used when constructing containers. This policy ensures that a container's base, found in an OCI annotation, is in a cluster-wide allow list.", + "remarks": "rule_set_0" + }, + { + "name": "Parameter_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "allowed_baseimages", + "remarks": "rule_set_0" + }, + { + "name": "Parameter_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Allowed baseimages", + "remarks": "rule_set_0" + }, + { + "name": "Parameter_Value_Alternatives", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "gcr.io/distroless/static:root", + "remarks": "rule_set_0" + }, + { + "name": "Check_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "allowed-base-images", + "remarks": "rule_set_0" + }, + { + "name": "Check_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Building images which specify a base as their origin is a good start to improving supply chain security, but over time organizations may want to build an allow list of specific base images which are allowed to be used when constructing containers. This policy ensures that a container's base, found in an OCI annotation, is in a cluster-wide allow list.", + "remarks": "rule_set_0" + }, + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "disallow-capabilities", + "remarks": "rule_set_1" + }, + { + "name": "Rule_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Images coming from certain registries require authentication in order to pull them, and the kubelet uses this information in the form of an imagePullSecret to pull those images on behalf of your Pod. This policy searches for images coming from a registry called `corp.reg.com` and, if found, will mutate the Pod to add an IimagePullSecret called `my-secret`.", + "remarks": "rule_set_1" + }, + { + "name": "Check_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "disallow-capabilities", + "remarks": "rule_set_1" + }, + { + "name": "Check_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Adding capabilities beyond those listed in the policy must be disallowed.", + "remarks": "rule_set_1" + } + ], + "control-implementations": [ + { + "uuid": "79fad5e8-f13f-413a-b3c2-b5ffed1d82ad", + "source": "https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json", + "description": "NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE", + "set-parameters": [ + { + "param-id": "allowed_baseimages", + "values": [ + "gcr.io/distroless/static:root" + ] + } + ], + "implemented-requirements": [ + { + "uuid": "552c000b-a4ee-4ba8-87d6-212cf95d120d", + "control-id": "cm-2", + "description": "", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "allowed-base-images" + } + ] + }, + { + "uuid": "5512dbcb-cecf-42ae-9441-a1b000da8a27", + "control-id": "cm-2.1", + "description": "", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "disallow-capabilities" + } + ] + } + ] + } + ] + }, + { + "uuid": "79ddf370-dc3e-4a68-9d85-e1b1b83792fc", + "type": "Validation", + "title": "Kyverno", + "description": "Kyverno as Policy Validation Point", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "allowed-base-images", + "remarks": "rule_set_2" + }, + { + "name": "Rule_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Building images which specify a base as their origin is a good start to improving supply chain security, but over time organizations may want to build an allow list of specific base images which are allowed to be used when constructing containers. This policy ensures that a container's base, found in an OCI annotation, is in a cluster-wide allow list.", + "remarks": "rule_set_2" + }, + { + "name": "Check_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "allowed-base-images", + "remarks": "rule_set_2" + }, + { + "name": "Check_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Building images which specify a base as their origin is a good start to improving supply chain security, but over time organizations may want to build an allow list of specific base images which are allowed to be used when constructing containers. This policy ensures that a container's base, found in an OCI annotation, is in a cluster-wide allow list.", + "remarks": "rule_set_2" + }, + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "disallow-capabilities", + "remarks": "rule_set_3" + }, + { + "name": "Rule_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Images coming from certain registries require authentication in order to pull them, and the kubelet uses this information in the form of an imagePullSecret to pull those images on behalf of your Pod. This policy searches for images coming from a registry called `corp.reg.com` and, if found, will mutate the Pod to add an IimagePullSecret called `my-secret`.", + "remarks": "rule_set_3" + }, + { + "name": "Check_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "disallow-capabilities", + "remarks": "rule_set_3" + }, + { + "name": "Check_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Adding capabilities beyond those listed in the policy must be disallowed.", + "remarks": "rule_set_3" + } + ], + "control-implementations": [ + { + "uuid": "6c215829-fe51-4ee9-a303-1d61301c24e2", + "source": "https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json", + "description": "NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE", + "implemented-requirements": [ + { + "uuid": "f06dbc3b-f486-40c1-8e25-6041a8697bd5", + "control-id": "na", + "description": "", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "allowed-base-images" + }, + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "disallow-capabilities" + } + ] + } + ] + } + ] + } + ] + } +} \ No newline at end of file diff --git a/plugins_public/tests/data/kyverno/deliverable-policy/allowed-base-images/02-setup-cm.yaml b/plugins_public/tests/data/kyverno/deliverable-policy/allowed-base-images/02-setup-cm.yaml new file mode 100644 index 0000000..e1df625 --- /dev/null +++ b/plugins_public/tests/data/kyverno/deliverable-policy/allowed-base-images/02-setup-cm.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: platform +--- +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: platform + name: baseimages +data: + allowedbaseimages: 'gcr.io/distroless/static:root' \ No newline at end of file diff --git a/plugins_public/tests/data/kyverno/deliverable-policy/allowed-base-images/allowed-base-images.yaml b/plugins_public/tests/data/kyverno/deliverable-policy/allowed-base-images/allowed-base-images.yaml new file mode 100644 index 0000000..94bd200 --- /dev/null +++ b/plugins_public/tests/data/kyverno/deliverable-policy/allowed-base-images/allowed-base-images.yaml @@ -0,0 +1,58 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: allowed-base-images + annotations: + policies.kyverno.io/title: Allowed Base Images + policies.kyverno.io/category: Other + policies.kyverno.io/severity: medium + kyverno.io/kyverno-version: 1.7.0 + policies.kyverno.io/minversion: 1.7.0 + kyverno.io/kubernetes-version: "1.23" + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + Building images which specify a base as their origin is a good start + to improving supply chain security, but over time organizations + may want to build an allow list of specific base images which + are allowed to be used when constructing containers. This policy ensures + that a container's base, found in an OCI annotation, is in a cluster-wide + allow list. +spec: + validationFailureAction: audit + rules: + - name: allowed-base-images + match: + any: + - resources: + kinds: + - Pod + preconditions: + all: + - key: "{{request.operation || 'BACKGROUND'}}" + operator: NotEquals + value: DELETE + context: + - name: baseimages + configMap: + name: baseimages + namespace: platform + validate: + message: >- + This container image's base is not in the approved list or is not specified. Only pre-approved + base images may be used. Please contact the platform team for assistance. + foreach: + - list: "request.object.spec.containers" + context: + - name: imageData + imageRegistry: + reference: "{{ element.image }}" + - name: basename + variable: + jmesPath: imageData.manifest.annotations."org.opencontainers.image.base.name" + default: '' + deny: + conditions: + all: + - key: "{{ basename }}" + operator: AnyNotIn + value: "{{ baseimages.data.allowedbaseimages }}" diff --git a/plugins_public/tests/data/kyverno/deliverable-policy/disallow-capabilities/disallow-capabilities.yaml b/plugins_public/tests/data/kyverno/deliverable-policy/disallow-capabilities/disallow-capabilities.yaml new file mode 100644 index 0000000..857a4db --- /dev/null +++ b/plugins_public/tests/data/kyverno/deliverable-policy/disallow-capabilities/disallow-capabilities.yaml @@ -0,0 +1,53 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: disallow-capabilities + annotations: + policies.kyverno.io/title: Disallow Capabilities + policies.kyverno.io/category: Pod Security Standards (Baseline) + policies.kyverno.io/severity: medium + kyverno.io/kyverno-version: 1.6.0 + policies.kyverno.io/minversion: 1.6.0 + kyverno.io/kubernetes-version: "1.22-1.23" + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + Adding capabilities beyond those listed in the policy must be disallowed. +spec: + validationFailureAction: audit + background: true + rules: + - name: adding-capabilities + match: + any: + - resources: + kinds: + - Pod + preconditions: + all: + - key: "{{ request.operation || 'BACKGROUND' }}" + operator: NotEquals + value: DELETE + validate: + message: >- + Any capabilities added beyond the allowed list (AUDIT_WRITE, CHOWN, DAC_OVERRIDE, FOWNER, + FSETID, KILL, MKNOD, NET_BIND_SERVICE, SETFCAP, SETGID, SETPCAP, SETUID, SYS_CHROOT) + are disallowed. + deny: + conditions: + all: + - key: "{{ request.object.spec.[ephemeralContainers, initContainers, containers][].securityContext.capabilities.add[] }}" + operator: AnyNotIn + value: + - AUDIT_WRITE + - CHOWN + - DAC_OVERRIDE + - FOWNER + - FSETID + - KILL + - MKNOD + - NET_BIND_SERVICE + - SETFCAP + - SETGID + - SETPCAP + - SETUID + - SYS_CHROOT \ No newline at end of file diff --git a/plugins_public/tests/data/kyverno/policy-resources/add-imagepullsecrets/add-imagepullsecrets.yaml b/plugins_public/tests/data/kyverno/policy-resources/add-imagepullsecrets/add-imagepullsecrets.yaml new file mode 100644 index 0000000..97da96e --- /dev/null +++ b/plugins_public/tests/data/kyverno/policy-resources/add-imagepullsecrets/add-imagepullsecrets.yaml @@ -0,0 +1,30 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: add-imagepullsecrets + annotations: + policies.kyverno.io/title: Add imagePullSecrets + policies.kyverno.io/category: Sample + policies.kyverno.io/subject: Pod + policies.kyverno.io/minversion: 1.6.0 + policies.kyverno.io/description: >- + Images coming from certain registries require authentication in order to pull them, + and the kubelet uses this information in the form of an imagePullSecret to pull + those images on behalf of your Pod. This policy searches for images coming from a + registry called `corp.reg.com` and, if found, will mutate the Pod to add an + imagePullSecret called `my-secret`. +spec: + rules: + - name: add-imagepullsecret + match: + any: + - resources: + kinds: + - Pod + mutate: + patchStrategicMerge: + spec: + containers: + - <(image): "corp.reg.com/*" + imagePullSecrets: + - name: my-secret \ No newline at end of file diff --git a/plugins_public/tests/data/kyverno/policy-resources/allowed-base-images/02-setup-cm.yaml b/plugins_public/tests/data/kyverno/policy-resources/allowed-base-images/02-setup-cm.yaml new file mode 100644 index 0000000..2cfaf1e --- /dev/null +++ b/plugins_public/tests/data/kyverno/policy-resources/allowed-base-images/02-setup-cm.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: platform +--- +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: platform + name: baseimages +data: + allowedbaseimages: '{{ allowed_baseimages|default("path/to/base/image:tag", true) }}' \ No newline at end of file diff --git a/plugins_public/tests/data/kyverno/policy-resources/allowed-base-images/allowed-base-images.yaml b/plugins_public/tests/data/kyverno/policy-resources/allowed-base-images/allowed-base-images.yaml new file mode 100644 index 0000000..94bd200 --- /dev/null +++ b/plugins_public/tests/data/kyverno/policy-resources/allowed-base-images/allowed-base-images.yaml @@ -0,0 +1,58 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: allowed-base-images + annotations: + policies.kyverno.io/title: Allowed Base Images + policies.kyverno.io/category: Other + policies.kyverno.io/severity: medium + kyverno.io/kyverno-version: 1.7.0 + policies.kyverno.io/minversion: 1.7.0 + kyverno.io/kubernetes-version: "1.23" + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + Building images which specify a base as their origin is a good start + to improving supply chain security, but over time organizations + may want to build an allow list of specific base images which + are allowed to be used when constructing containers. This policy ensures + that a container's base, found in an OCI annotation, is in a cluster-wide + allow list. +spec: + validationFailureAction: audit + rules: + - name: allowed-base-images + match: + any: + - resources: + kinds: + - Pod + preconditions: + all: + - key: "{{request.operation || 'BACKGROUND'}}" + operator: NotEquals + value: DELETE + context: + - name: baseimages + configMap: + name: baseimages + namespace: platform + validate: + message: >- + This container image's base is not in the approved list or is not specified. Only pre-approved + base images may be used. Please contact the platform team for assistance. + foreach: + - list: "request.object.spec.containers" + context: + - name: imageData + imageRegistry: + reference: "{{ element.image }}" + - name: basename + variable: + jmesPath: imageData.manifest.annotations."org.opencontainers.image.base.name" + default: '' + deny: + conditions: + all: + - key: "{{ basename }}" + operator: AnyNotIn + value: "{{ baseimages.data.allowedbaseimages }}" diff --git a/plugins_public/tests/data/kyverno/policy-resources/disallow-capabilities/disallow-capabilities.yaml b/plugins_public/tests/data/kyverno/policy-resources/disallow-capabilities/disallow-capabilities.yaml new file mode 100644 index 0000000..857a4db --- /dev/null +++ b/plugins_public/tests/data/kyverno/policy-resources/disallow-capabilities/disallow-capabilities.yaml @@ -0,0 +1,53 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: disallow-capabilities + annotations: + policies.kyverno.io/title: Disallow Capabilities + policies.kyverno.io/category: Pod Security Standards (Baseline) + policies.kyverno.io/severity: medium + kyverno.io/kyverno-version: 1.6.0 + policies.kyverno.io/minversion: 1.6.0 + kyverno.io/kubernetes-version: "1.22-1.23" + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + Adding capabilities beyond those listed in the policy must be disallowed. +spec: + validationFailureAction: audit + background: true + rules: + - name: adding-capabilities + match: + any: + - resources: + kinds: + - Pod + preconditions: + all: + - key: "{{ request.operation || 'BACKGROUND' }}" + operator: NotEquals + value: DELETE + validate: + message: >- + Any capabilities added beyond the allowed list (AUDIT_WRITE, CHOWN, DAC_OVERRIDE, FOWNER, + FSETID, KILL, MKNOD, NET_BIND_SERVICE, SETFCAP, SETGID, SETPCAP, SETUID, SYS_CHROOT) + are disallowed. + deny: + conditions: + all: + - key: "{{ request.object.spec.[ephemeralContainers, initContainers, containers][].securityContext.capabilities.add[] }}" + operator: AnyNotIn + value: + - AUDIT_WRITE + - CHOWN + - DAC_OVERRIDE + - FOWNER + - FSETID + - KILL + - MKNOD + - NET_BIND_SERVICE + - SETFCAP + - SETGID + - SETPCAP + - SETUID + - SYS_CHROOT \ No newline at end of file diff --git a/plugins_public/tests/data/kyverno/policyreports.wgpolicyk8s.io.yaml b/plugins_public/tests/data/kyverno/policyreports.wgpolicyk8s.io.yaml new file mode 100644 index 0000000..310a8f0 --- /dev/null +++ b/plugins_public/tests/data/kyverno/policyreports.wgpolicyk8s.io.yaml @@ -0,0 +1,1311 @@ +apiVersion: v1 +items: +- apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + metadata: + creationTimestamp: "2024-04-14T07:19:19Z" + generation: 1 + labels: + app.kubernetes.io/managed-by: kyverno + cpol.kyverno.io/allowed-base-images: "22432" + name: cpol-allowed-base-images + namespace: kube-system + resourceVersion: "22649" + uid: 5d36af80-eaf8-432e-b7dd-c9c993e13c10 + results: + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: kube-scheduler-kind-control-plane + namespace: kube-system + uid: 5c5d8e06-724c-439f-a9be-3ae34b0c6083 + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079157 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: coredns-5d78c9869d-gc25q + namespace: kube-system + uid: 621caa1d-897d-4366-8906-841ba56c1fdd + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079157 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: kindnet-pbb9l + namespace: kube-system + uid: 74db5c25-74ca-457d-96e3-0d7d0dc39b19 + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079159 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: etcd-kind-control-plane + namespace: kube-system + uid: 8f2aebd7-7957-4037-8509-34596db786ac + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079156 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: kube-apiserver-kind-control-plane + namespace: kube-system + uid: a0703256-75e4-4bba-83c8-c8df32866156 + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079154 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: kube-proxy-zbddb + namespace: kube-system + uid: aee2dfc5-9c05-4b6f-b7a7-6d87bdbd2eab + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079157 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: coredns-5d78c9869d-2rbnq + namespace: kube-system + uid: d053eefe-8d34-4ffa-9550-8d68e6f37e08 + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079154 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: kube-controller-manager-kind-control-plane + namespace: kube-system + uid: d420e878-2ba7-45e3-afb4-af859d0891af + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079158 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: DaemonSet + name: kindnet + namespace: kube-system + uid: 73917941-f4d3-444f-8d0f-be93ba1e4e2b + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079150 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: DaemonSet + name: kube-proxy + namespace: kube-system + uid: 78cf0d9f-c3b2-488d-b596-0e4729025aee + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079150 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: ReplicaSet + name: coredns-5d78c9869d + namespace: kube-system + uid: 919c840d-63cf-4293-8a64-0fd0de15121f + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079129 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: Deployment + name: coredns + namespace: kube-system + uid: d7418bd6-4c02-4344-864b-d710ee03b7e2 + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079150 + summary: + error: 0 + fail: 12 + pass: 0 + skip: 0 + warn: 0 +- apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + metadata: + creationTimestamp: "2024-04-14T07:19:19Z" + generation: 2 + labels: + app.kubernetes.io/managed-by: kyverno + cpol.kyverno.io/disallow-capabilities: "22434" + name: cpol-disallow-capabilities + namespace: kube-system + resourceVersion: "22763" + uid: 570a67ea-3fde-496c-afd7-5e9dfa417601 + results: + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: kube-scheduler-kind-control-plane + namespace: kube-system + uid: 5c5d8e06-724c-439f-a9be-3ae34b0c6083 + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079157 + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: coredns-5d78c9869d-gc25q + namespace: kube-system + uid: 621caa1d-897d-4366-8906-841ba56c1fdd + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079157 + - category: Pod Security Standards (Baseline) + message: Any capabilities added beyond the allowed list (AUDIT_WRITE, CHOWN, DAC_OVERRIDE, + FOWNER, FSETID, KILL, MKNOD, NET_BIND_SERVICE, SETFCAP, SETGID, SETPCAP, SETUID, + SYS_CHROOT) are disallowed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: kindnet-pbb9l + namespace: kube-system + uid: 74db5c25-74ca-457d-96e3-0d7d0dc39b19 + result: fail + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079159 + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: etcd-kind-control-plane + namespace: kube-system + uid: 8f2aebd7-7957-4037-8509-34596db786ac + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079156 + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: kube-apiserver-kind-control-plane + namespace: kube-system + uid: a0703256-75e4-4bba-83c8-c8df32866156 + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079154 + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: kube-proxy-zbddb + namespace: kube-system + uid: aee2dfc5-9c05-4b6f-b7a7-6d87bdbd2eab + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079157 + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: coredns-5d78c9869d-2rbnq + namespace: kube-system + uid: d053eefe-8d34-4ffa-9550-8d68e6f37e08 + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079154 + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: kube-controller-manager-kind-control-plane + namespace: kube-system + uid: d420e878-2ba7-45e3-afb4-af859d0891af + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079158 + - category: Pod Security Standards (Baseline) + message: Any capabilities added beyond the allowed list (AUDIT_WRITE, CHOWN, DAC_OVERRIDE, + FOWNER, FSETID, KILL, MKNOD, NET_BIND_SERVICE, SETFCAP, SETGID, SETPCAP, SETUID, + SYS_CHROOT) are disallowed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: DaemonSet + name: kindnet + namespace: kube-system + uid: 73917941-f4d3-444f-8d0f-be93ba1e4e2b + result: fail + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079150 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: DaemonSet + name: kube-proxy + namespace: kube-system + uid: 78cf0d9f-c3b2-488d-b596-0e4729025aee + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079150 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: ReplicaSet + name: coredns-5d78c9869d + namespace: kube-system + uid: 919c840d-63cf-4293-8a64-0fd0de15121f + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079159 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: Deployment + name: coredns + namespace: kube-system + uid: d7418bd6-4c02-4344-864b-d710ee03b7e2 + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079150 + summary: + error: 0 + fail: 2 + pass: 10 + skip: 0 + warn: 0 +- apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + metadata: + creationTimestamp: "2024-04-14T07:19:29Z" + generation: 1 + labels: + app.kubernetes.io/managed-by: kyverno + cpol.kyverno.io/allowed-base-images: "22432" + name: cpol-allowed-base-images + namespace: kyverno + resourceVersion: "22693" + uid: e1f75f6e-c64e-40e4-b162-5ab8f5831392 + results: + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: kyverno-admission-controller-7cd788c8dd-gdnhp + namespace: kyverno + uid: 149a831c-bfbd-487e-83f5-59685cc3e7ae + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079155 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: kyverno-reports-controller-7f94855747-tmnhr + namespace: kyverno + uid: 3113da8b-778d-4650-a00b-8244f46383b6 + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079159 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: kyverno-cleanup-admission-reports-28551310-cc4k7 + namespace: kyverno + uid: 815cbb34-eeea-43ab-977a-ee509cd3c8b4 + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079157 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: kyverno-cleanup-cluster-admission-reports-28551310-m4ld4 + namespace: kyverno + uid: ad02a4a0-765d-41fe-ba8d-4d8bc1f4bbb1 + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079157 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: kyverno-cleanup-controller-ddf458755-9bnlb + namespace: kyverno + uid: d593fd38-2d90-4178-acd2-673a6b9dcbe7 + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079156 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: kyverno-background-controller-74599787cf-s6nm2 + namespace: kyverno + uid: dd188800-5da7-4449-8e97-4333b5c71762 + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079155 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: Deployment + name: kyverno-cleanup-controller + namespace: kyverno + uid: 0ec446db-1759-4c62-b08f-c56cd15ae133 + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079152 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: batch/v1 + kind: Job + name: kyverno-cleanup-cluster-admission-reports-28551310 + namespace: kyverno + uid: 1bbefe68-2a6f-4f98-a578-7830ab2ddba7 + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079153 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: ReplicaSet + name: kyverno-admission-controller-7cd788c8dd + namespace: kyverno + uid: 2dce65ca-0421-4189-a2d9-c5b0f3509eb0 + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079139 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: batch/v1 + kind: Job + name: kyverno-cleanup-admission-reports-28551310 + namespace: kyverno + uid: 7e7fd9ee-2663-45ec-8fc5-2b8224af97be + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079154 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: Deployment + name: kyverno-background-controller + namespace: kyverno + uid: a061c459-8d2d-4dfd-95a5-3a74d74be6ad + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079151 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: ReplicaSet + name: kyverno-cleanup-controller-ddf458755 + namespace: kyverno + uid: b64c38ba-5d41-4b05-85c2-04a0fa92d671 + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079140 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: ReplicaSet + name: kyverno-background-controller-74599787cf + namespace: kyverno + uid: bdd4f14b-5f6b-463d-a5d2-3ee155150f41 + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079138 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: Deployment + name: kyverno-reports-controller + namespace: kyverno + uid: c07941a1-6078-4f18-bd94-ad1ecbd401b0 + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079152 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: ReplicaSet + name: kyverno-reports-controller-7f94855747 + namespace: kyverno + uid: c50add3f-7021-4272-8b17-17dc894a1d14 + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079140 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: Deployment + name: kyverno-admission-controller + namespace: kyverno + uid: d76bafdd-ff22-4179-a8b2-ee74991635fc + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079151 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: batch/v1 + kind: CronJob + name: kyverno-cleanup-cluster-admission-reports + namespace: kyverno + uid: 61fb66f3-6ae6-4502-9945-f82c37bf1a11 + result: fail + rule: autogen-cronjob-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079149 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: batch/v1 + kind: CronJob + name: kyverno-cleanup-admission-reports + namespace: kyverno + uid: 88974b3b-c9df-440f-aeb4-039221c8aa6c + result: fail + rule: autogen-cronjob-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079149 + summary: + error: 0 + fail: 18 + pass: 0 + skip: 0 + warn: 0 +- apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + metadata: + creationTimestamp: "2024-04-14T07:19:29Z" + generation: 1 + labels: + app.kubernetes.io/managed-by: kyverno + cpol.kyverno.io/disallow-capabilities: "22434" + name: cpol-disallow-capabilities + namespace: kyverno + resourceVersion: "22694" + uid: 216df56b-52cb-4fdc-a356-263a0d03a6a4 + results: + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: kyverno-admission-controller-7cd788c8dd-gdnhp + namespace: kyverno + uid: 149a831c-bfbd-487e-83f5-59685cc3e7ae + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079155 + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: kyverno-reports-controller-7f94855747-tmnhr + namespace: kyverno + uid: 3113da8b-778d-4650-a00b-8244f46383b6 + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079159 + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: kyverno-cleanup-admission-reports-28551310-cc4k7 + namespace: kyverno + uid: 815cbb34-eeea-43ab-977a-ee509cd3c8b4 + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079157 + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: kyverno-cleanup-cluster-admission-reports-28551310-m4ld4 + namespace: kyverno + uid: ad02a4a0-765d-41fe-ba8d-4d8bc1f4bbb1 + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079157 + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: kyverno-cleanup-controller-ddf458755-9bnlb + namespace: kyverno + uid: d593fd38-2d90-4178-acd2-673a6b9dcbe7 + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079156 + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: kyverno-background-controller-74599787cf-s6nm2 + namespace: kyverno + uid: dd188800-5da7-4449-8e97-4333b5c71762 + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079155 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: Deployment + name: kyverno-cleanup-controller + namespace: kyverno + uid: 0ec446db-1759-4c62-b08f-c56cd15ae133 + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079152 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: batch/v1 + kind: Job + name: kyverno-cleanup-cluster-admission-reports-28551310 + namespace: kyverno + uid: 1bbefe68-2a6f-4f98-a578-7830ab2ddba7 + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079153 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: ReplicaSet + name: kyverno-admission-controller-7cd788c8dd + namespace: kyverno + uid: 2dce65ca-0421-4189-a2d9-c5b0f3509eb0 + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079129 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: batch/v1 + kind: Job + name: kyverno-cleanup-admission-reports-28551310 + namespace: kyverno + uid: 7e7fd9ee-2663-45ec-8fc5-2b8224af97be + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079154 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: Deployment + name: kyverno-background-controller + namespace: kyverno + uid: a061c459-8d2d-4dfd-95a5-3a74d74be6ad + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079151 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: ReplicaSet + name: kyverno-cleanup-controller-ddf458755 + namespace: kyverno + uid: b64c38ba-5d41-4b05-85c2-04a0fa92d671 + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079140 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: ReplicaSet + name: kyverno-background-controller-74599787cf + namespace: kyverno + uid: bdd4f14b-5f6b-463d-a5d2-3ee155150f41 + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079139 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: Deployment + name: kyverno-reports-controller + namespace: kyverno + uid: c07941a1-6078-4f18-bd94-ad1ecbd401b0 + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079152 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: ReplicaSet + name: kyverno-reports-controller-7f94855747 + namespace: kyverno + uid: c50add3f-7021-4272-8b17-17dc894a1d14 + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079140 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: Deployment + name: kyverno-admission-controller + namespace: kyverno + uid: d76bafdd-ff22-4179-a8b2-ee74991635fc + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079151 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-cronjob-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: batch/v1 + kind: CronJob + name: kyverno-cleanup-cluster-admission-reports + namespace: kyverno + uid: 61fb66f3-6ae6-4502-9945-f82c37bf1a11 + result: pass + rule: autogen-cronjob-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079149 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-cronjob-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: batch/v1 + kind: CronJob + name: kyverno-cleanup-admission-reports + namespace: kyverno + uid: 88974b3b-c9df-440f-aeb4-039221c8aa6c + result: pass + rule: autogen-cronjob-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079149 + summary: + error: 0 + fail: 0 + pass: 18 + skip: 0 + warn: 0 +- apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + metadata: + creationTimestamp: "2024-04-14T07:19:22Z" + generation: 1 + labels: + app.kubernetes.io/managed-by: kyverno + cpol.kyverno.io/allowed-base-images: "22432" + name: cpol-allowed-base-images + namespace: local-path-storage + resourceVersion: "22670" + uid: 7475e833-54a2-413c-b54a-648ce5d9abf9 + results: + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: v1 + kind: Pod + name: local-path-provisioner-6bc4bddd6b-vlmww + namespace: local-path-storage + uid: 5863d467-1533-4721-8387-d620c959800e + result: fail + rule: allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079160 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: ReplicaSet + name: local-path-provisioner-6bc4bddd6b + namespace: local-path-storage + uid: 5bc38239-ae62-4d6c-bd51-ffda62e44843 + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079132 + - category: Other + message: 'validation failure: This container image''s base is not in the approved + list or is not specified. Only pre-approved base images may be used. Please + contact the platform team for assistance.' + policy: allowed-base-images + resources: + - apiVersion: apps/v1 + kind: Deployment + name: local-path-provisioner + namespace: local-path-storage + uid: 94957b8f-76ce-457e-a3ed-628e4403ebc5 + result: fail + rule: autogen-allowed-base-images + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079153 + summary: + error: 0 + fail: 3 + pass: 0 + skip: 0 + warn: 0 +- apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + metadata: + creationTimestamp: "2024-04-14T07:19:22Z" + generation: 1 + labels: + app.kubernetes.io/managed-by: kyverno + cpol.kyverno.io/disallow-capabilities: "22434" + name: cpol-disallow-capabilities + namespace: local-path-storage + resourceVersion: "22671" + uid: adcdbdac-c1cc-4bd3-9077-ba67684e35f3 + results: + - category: Pod Security Standards (Baseline) + message: validation rule 'adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: v1 + kind: Pod + name: local-path-provisioner-6bc4bddd6b-vlmww + namespace: local-path-storage + uid: 5863d467-1533-4721-8387-d620c959800e + result: pass + rule: adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079160 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: ReplicaSet + name: local-path-provisioner-6bc4bddd6b + namespace: local-path-storage + uid: 5bc38239-ae62-4d6c-bd51-ffda62e44843 + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079159 + - category: Pod Security Standards (Baseline) + message: validation rule 'autogen-adding-capabilities' passed. + policy: disallow-capabilities + resources: + - apiVersion: apps/v1 + kind: Deployment + name: local-path-provisioner + namespace: local-path-storage + uid: 94957b8f-76ce-457e-a3ed-628e4403ebc5 + result: pass + rule: autogen-adding-capabilities + scored: true + severity: medium + source: kyverno + timestamp: + nanos: 0 + seconds: 1713079153 + summary: + error: 0 + fail: 0 + pass: 3 + skip: 0 + warn: 0 +kind: List +metadata: + resourceVersion: "" diff --git a/plugins_public/tests/data/ocm/component-definition.csv b/plugins_public/tests/data/ocm/component-definition.csv new file mode 100644 index 0000000..917ed12 --- /dev/null +++ b/plugins_public/tests/data/ocm/component-definition.csv @@ -0,0 +1,8 @@ +$$Component_Title,$$Component_Description,$$Component_Type,$$Control_Id_List,$$Rule_Id,$$Rule_Description,$Parameter_Id,$Parameter_Description,$Parameter_Value_Alternatives,$Parameter_Value_Default,$$Profile_Source,$$Profile_Description,Rule_Actual_State_Data_Request_Evidence_Format_Reference_URL_list,Rule_Actual_State_TimeToLive,$Check_Id,$Check_Description,Fetcher_id,Fetcher_Description,Fix_id,Fix_Description,Rule_implementation_status,Rule_POAM_Reference_URL,$$Namespace +A human readable name for the component.,A description of the component including information about its function.,A category describing the purpose of the component. ALLOWED VALUES interconnection:software:hardware:service:physical:process-procedure:plan:guidance:standard:validation:,A list of textual labels that uniquely identify the controls or statements that the component implements.,A textual label that uniquely identifies a policy (desired state) that can be used to reference it elsewhere in this or other documents.,A description of the policy (desired state) including information about its purpose and scope.,A textual label that uniquely identifies the parameter associated with that policy (desired state) or controls implemented by the policy (desired state).,A description of the parameter including the purpose and use of the parameter.,ONLY for the policy (desired state) parameters: A value or set of values the parameter can take. The catalog parameters values are defined in the catalog. ,"A value recommended by Compliance Team in this profile for the parameter of the control or policy (desired state). If a CIS-benchmark exists, the default default could be the CIS-benchmark recommanded value.",A URL reference to the source catalog or profile for which this component is implementing controls for. A profile designates a selection and configuration of controls from one or more catalogs,A description of the profile.,A list of URL references that contain the Actual State Data Model (eg schema or swager API or procedure template or terraform schema). Needed by the fetcher developer. ,A TimeToLive value of the duration of time the actual state is valid before it becomes stale or obsolite or overriden. Needed by the fetcher developer. ,A textual label that uniquely identifies a check of the policy (desired state) that can be used to reference it elsewhere in this or other documents.,A description of the check of the policy (desired state) including the method (interview or examine or test) and procedure details.,A textual label that uniquely identifies a collector of the actual state (evidence) associated with the policy (desired state) that can be used to reference it elsewhere in this or other documents.,A description of the collector of the actual state (evidence) associated with the policy (desired state) including the method (interview or examine or API) and questionaire or API details.,A textual label that uniquely identifies the fix of the failed policy.,A description of the fix to remediate the failed policy.,Indicates the degree to which the a given policy is implemented. ALLOWED VALUES: IMPLEMENTED: The control is fully implemented. PARTIAL: The control is partially implemented. PLANNED: There is a plan for implementing the control as explained in the remarks. ALTERNATIVE: There is an alternative implementation for this control as explained in the remarks. NOT-APPLICABLE: This control does not apply to this system as justified in the remarks.,A URL reference to the Plan of Action and Milestones this component may be subjected to for remediation or deviation or mitigation in case of the policy (desired state) non compliance or error or failure. ,"A namespace qualifying the property's name. This allows different organizations to associate distinct semantics with the same name. Used in conjunction with ""class"" as the ontology concept. " +Managed Kubernetes,Managed Kubernetes cluster,Service,cm-2,policy-deployment,Ensure deployment configuration is securely set up,minimum_nginx_deployment_replicas,Minimum number of NGINX pod,3,3,https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json,NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE,,,policy-deployment,Ensure NGINX is deployed and running with given minimum instances,,,,,,,http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud +Managed Kubernetes,Managed Kubernetes cluster,Service,ac-1,policy-disallowed-roles,Ensure roles are set to only allowed values,,,,,https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json,NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE,,,policy-disallowed-roles,Ensure roles are set to only allowed values,,,,,,,http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud +Managed Kubernetes,Managed Kubernetes cluster,Service,cm-6,policy-high-scan,Ensure scan is enabled with high level,,,,,https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json,NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE,,,policy-high-scan,Ensure scan is enabled with high level,,,,,,,http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud +OCM,OCM as Policy Validation Point,Validation,na,policy-deployment,Ensure NGINX is deployed and running with given minimum instances,,,,,https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json,NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE,,,policy-deployment,Ensure NGINX is deployed and running with given minimum instances,,,,,,,http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud +OCM,OCM as Policy Validation Point,Validation,na,policy-disallowed-roles,Ensure roles are set to only allowed values,,,,,https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json,NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE,,,policy-disallowed-roles,Ensure roles are set to only allowed values,,,,,,,http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud +OCM,OCM as Policy Validation Point,Validation,na,policy-high-scan,Ensure scan is enabled with high level,,,,,https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json,NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE,,,policy-high-scan,Ensure scan is enabled with high level,,,,,,,http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud \ No newline at end of file diff --git a/plugins_public/tests/data/ocm/component-definition.json b/plugins_public/tests/data/ocm/component-definition.json new file mode 100644 index 0000000..538d755 --- /dev/null +++ b/plugins_public/tests/data/ocm/component-definition.json @@ -0,0 +1,275 @@ +{ + "component-definition": { + "uuid": "f78115b4-0d04-4324-b78a-31d8f25407ce", + "metadata": { + "title": "Component Definition for managed clusters", + "last-modified": "2024-04-14T08:51:31+00:00", + "version": "1.0", + "oscal-version": "1.0.4" + }, + "components": [ + { + "uuid": "c740b275-7c18-44fa-aa1d-ff5d99d569c5", + "type": "Service", + "title": "Managed Kubernetes", + "description": "Managed Kubernetes cluster", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-deployment", + "remarks": "rule_set_0" + }, + { + "name": "Rule_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure deployment configuration is securely set up", + "remarks": "rule_set_0" + }, + { + "name": "Parameter_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "minimum_nginx_deployment_replicas", + "remarks": "rule_set_0" + }, + { + "name": "Parameter_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Minimum number of NGINX pod", + "remarks": "rule_set_0" + }, + { + "name": "Parameter_Value_Alternatives", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "3", + "remarks": "rule_set_0" + }, + { + "name": "Check_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-deployment", + "remarks": "rule_set_0" + }, + { + "name": "Check_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure NGINX is deployed and running with given minimum instances", + "remarks": "rule_set_0" + }, + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-disallowed-roles", + "remarks": "rule_set_1" + }, + { + "name": "Rule_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure roles are set to only allowed values", + "remarks": "rule_set_1" + }, + { + "name": "Check_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-disallowed-roles", + "remarks": "rule_set_1" + }, + { + "name": "Check_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure roles are set to only allowed values", + "remarks": "rule_set_1" + }, + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-high-scan", + "remarks": "rule_set_2" + }, + { + "name": "Rule_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure scan is enabled with high level", + "remarks": "rule_set_2" + }, + { + "name": "Check_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-high-scan", + "remarks": "rule_set_2" + }, + { + "name": "Check_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure scan is enabled with high level", + "remarks": "rule_set_2" + } + ], + "control-implementations": [ + { + "uuid": "524a1e8e-284b-43d8-b220-5ce9177119f6", + "source": "https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json", + "description": "NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE", + "set-parameters": [ + { + "param-id": "minimum_nginx_deployment_replicas", + "values": [ + "3" + ] + } + ], + "implemented-requirements": [ + { + "uuid": "f241525c-83f6-4f3d-b114-b5e3e466a81d", + "control-id": "cm-2", + "description": "", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-deployment" + } + ] + }, + { + "uuid": "712186cc-785d-4dee-84bd-2377d04735ab", + "control-id": "ac-1", + "description": "", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-disallowed-roles" + } + ] + }, + { + "uuid": "232e98d5-1c3f-4f53-b0d6-e60a7fa70ac5", + "control-id": "cm-6", + "description": "", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-high-scan" + } + ] + } + ] + } + ] + }, + { + "uuid": "87ce7ffa-b432-4c2f-9780-b9aa67c8fb5c", + "type": "Validation", + "title": "OCM", + "description": "OCM as Policy Validation Point", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-deployment", + "remarks": "rule_set_3" + }, + { + "name": "Rule_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure NGINX is deployed and running with given minimum instances", + "remarks": "rule_set_3" + }, + { + "name": "Check_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-deployment", + "remarks": "rule_set_3" + }, + { + "name": "Check_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure NGINX is deployed and running with given minimum instances", + "remarks": "rule_set_3" + }, + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-disallowed-roles", + "remarks": "rule_set_4" + }, + { + "name": "Rule_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure roles are set to only allowed values", + "remarks": "rule_set_4" + }, + { + "name": "Check_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-disallowed-roles", + "remarks": "rule_set_4" + }, + { + "name": "Check_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure roles are set to only allowed values", + "remarks": "rule_set_4" + }, + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-high-scan", + "remarks": "rule_set_5" + }, + { + "name": "Rule_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure scan is enabled with high level", + "remarks": "rule_set_5" + }, + { + "name": "Check_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-high-scan", + "remarks": "rule_set_5" + }, + { + "name": "Check_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure scan is enabled with high level", + "remarks": "rule_set_5" + } + ], + "control-implementations": [ + { + "uuid": "2b342e42-7c5f-429f-835d-d3c8a5edd8fc", + "source": "https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json", + "description": "NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE", + "implemented-requirements": [ + { + "uuid": "bec41a64-d9ab-408f-bc6c-d00bf95b5b36", + "control-id": "na", + "description": "", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-deployment" + }, + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-disallowed-roles" + }, + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-high-scan" + } + ] + } + ] + } + ] + } + ] + } +} \ No newline at end of file diff --git a/plugins_public/tests/data/ocm/deliverable-policy/kustomization.yaml b/plugins_public/tests/data/ocm/deliverable-policy/kustomization.yaml new file mode 100644 index 0000000..50d97fb --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/kustomization.yaml @@ -0,0 +1,10 @@ +generators: +- ./policy-generator.yaml +patches: +- patch: '[{"op": "replace", "path": "/metadata/annotations/compliance-to-policy.component-title", + "value": "c2p test"}]' + target: + kind: PolicySet + name: c2p-test +resources: +- ./parameters.yaml diff --git a/plugins_public/tests/data/ocm/deliverable-policy/parameters.yaml b/plugins_public/tests/data/ocm/deliverable-policy/parameters.yaml new file mode 100644 index 0000000..31f13ef --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/parameters.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +data: + minimum_nginx_deployment_replicas: '3' +kind: ConfigMap +metadata: + name: c2p-parameters + namespace: c2p diff --git a/plugins_public/tests/data/ocm/deliverable-policy/policy-deployment/kustomization.yaml b/plugins_public/tests/data/ocm/deliverable-policy/policy-deployment/kustomization.yaml new file mode 100755 index 0000000..0573618 --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/policy-deployment/kustomization.yaml @@ -0,0 +1,2 @@ +generators: +- ./policy-generator.yaml diff --git a/plugins_public/tests/data/ocm/deliverable-policy/policy-deployment/policy-generator.yaml b/plugins_public/tests/data/ocm/deliverable-policy/policy-deployment/policy-generator.yaml new file mode 100755 index 0000000..89c829a --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/policy-deployment/policy-generator.yaml @@ -0,0 +1,23 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: PolicyGenerator +metadata: + name: policy-generator +policies: +- complianceType: musthave + consolidateManifests: true + manifests: + - path: ./policy-nginx-deployment + name: policy-deployment + orderManifests: false + remediationAction: inform + severity: low +policyDefaults: + categories: [] + consolidateManifests: false + controls: [] + namespace: c2p + orderManifests: false + placement: + clusterSelectors: + environment: dev + standards: [] diff --git a/plugins_public/tests/data/ocm/deliverable-policy/policy-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml b/plugins_public/tests/data/ocm/deliverable-policy/policy-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml new file mode 100755 index 0000000..8d59ace --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/policy-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + replicas: '{{hub fromConfigMap "c2p" "c2p-parameters" "minimum_nginx_deployment_replicas" | toInt hub}}' + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx:1.21.4 + name: nginx + ports: + - containerPort: 80 diff --git a/plugins_public/tests/data/ocm/deliverable-policy/policy-disallowed-roles/kustomization.yaml b/plugins_public/tests/data/ocm/deliverable-policy/policy-disallowed-roles/kustomization.yaml new file mode 100755 index 0000000..0573618 --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/policy-disallowed-roles/kustomization.yaml @@ -0,0 +1,2 @@ +generators: +- ./policy-generator.yaml diff --git a/plugins_public/tests/data/ocm/deliverable-policy/policy-disallowed-roles/policy-disallowed-roles-sample-role/Role.noname.0.yaml b/plugins_public/tests/data/ocm/deliverable-policy/policy-disallowed-roles/policy-disallowed-roles-sample-role/Role.noname.0.yaml new file mode 100755 index 0000000..bb259be --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/policy-disallowed-roles/policy-disallowed-roles-sample-role/Role.noname.0.yaml @@ -0,0 +1,9 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +rules: +- apiGroups: + - '*' + resources: + - '*' + verbs: + - '*' diff --git a/plugins_public/tests/data/ocm/deliverable-policy/policy-disallowed-roles/policy-generator.yaml b/plugins_public/tests/data/ocm/deliverable-policy/policy-disallowed-roles/policy-generator.yaml new file mode 100755 index 0000000..8bd0ef7 --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/policy-disallowed-roles/policy-generator.yaml @@ -0,0 +1,23 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: PolicyGenerator +metadata: + name: policy-generator +policies: +- complianceType: mustnothave + consolidateManifests: true + manifests: + - path: ./policy-disallowed-roles-sample-role + name: policy-disallowed-roles + orderManifests: false + remediationAction: inform + severity: high +policyDefaults: + categories: [] + consolidateManifests: false + controls: [] + namespace: c2p + orderManifests: false + placement: + clusterSelectors: + environment: dev + standards: [] diff --git a/plugins_public/tests/data/ocm/deliverable-policy/policy-generator.yaml b/plugins_public/tests/data/ocm/deliverable-policy/policy-generator.yaml new file mode 100644 index 0000000..56a38ed --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/policy-generator.yaml @@ -0,0 +1,89 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: PolicyGenerator +metadata: + name: policy-set +placementBindingDefaults: + name: policy-set +policies: +- categories: [] + complianceType: musthave + consolidateManifests: true + controls: [] + informGatekeeperPolicies: false + informKyvernoPolicies: false + manifests: + - ignorePending: false + path: ./policy-deployment/policy-nginx-deployment + name: policy-deployment + orderManifests: false + remediationAction: inform + severity: low + standards: [] +- categories: [] + complianceType: mustnothave + consolidateManifests: true + controls: [] + informGatekeeperPolicies: false + informKyvernoPolicies: false + manifests: + - ignorePending: false + path: ./policy-disallowed-roles/policy-disallowed-roles-sample-role + name: policy-disallowed-roles + orderManifests: false + remediationAction: inform + severity: high + standards: [] +- categories: [] + complianceType: mustnothave + consolidateManifests: false + controls: [] + informGatekeeperPolicies: false + informKyvernoPolicies: false + manifests: + - complianceType: musthave + ignorePending: false + path: ./policy-high-scan/compliance-high-scan + remediationAction: inform + severity: high + - complianceType: musthave + ignorePending: false + path: ./policy-high-scan/compliance-suite-high + remediationAction: inform + severity: high + - complianceType: mustnothave + ignorePending: false + path: ./policy-high-scan/compliance-suite-high-results + remediationAction: inform + severity: high + name: policy-high-scan + orderManifests: false + remediationAction: inform + severity: high + standards: [] +policyDefaults: + consolidateManifests: false + informGatekeeperPolicies: false + informKyvernoPolicies: false + namespace: c2p + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + orderManifests: false + placement: + labelSelector: + environment: dev +policySetDefaults: + placement: + labelSelector: + environment: dev +policySets: +- name: c2p-test + policies: + - policy-deployment + - policy-disallowed-roles + - policy-high-scan diff --git a/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/compliance-high-scan/ScanSettingBinding.high.0.yaml b/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/compliance-high-scan/ScanSettingBinding.high.0.yaml new file mode 100755 index 0000000..620bcd0 --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/compliance-high-scan/ScanSettingBinding.high.0.yaml @@ -0,0 +1,16 @@ +apiVersion: compliance.openshift.io/v1alpha1 +kind: ScanSettingBinding +metadata: + name: high + namespace: openshift-compliance +profiles: +- apiGroup: compliance.openshift.io/v1alpha1 + kind: Profile + name: ocp4-high +- apiGroup: compliance.openshift.io/v1alpha1 + kind: Profile + name: ocp4-high-node +settingsRef: + apiGroup: compliance.openshift.io/v1alpha1 + kind: ScanSetting + name: default diff --git a/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/compliance-suite-high-results/ComplianceCheckResult.noname.0.yaml b/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/compliance-suite-high-results/ComplianceCheckResult.noname.0.yaml new file mode 100755 index 0000000..e1cba9b --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/compliance-suite-high-results/ComplianceCheckResult.noname.0.yaml @@ -0,0 +1,7 @@ +apiVersion: compliance.openshift.io/v1alpha1 +kind: ComplianceCheckResult +metadata: + labels: + compliance.openshift.io/check-status: FAIL + compliance.openshift.io/suite: high + namespace: openshift-compliance diff --git a/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/compliance-suite-high/ComplianceSuite.high.0.yaml b/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/compliance-suite-high/ComplianceSuite.high.0.yaml new file mode 100755 index 0000000..cdc5b90 --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/compliance-suite-high/ComplianceSuite.high.0.yaml @@ -0,0 +1,7 @@ +apiVersion: compliance.openshift.io/v1alpha1 +kind: ComplianceSuite +metadata: + name: high + namespace: openshift-compliance +status: + phase: DONE diff --git a/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/kustomization.yaml b/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/kustomization.yaml new file mode 100755 index 0000000..0573618 --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/kustomization.yaml @@ -0,0 +1,2 @@ +generators: +- ./policy-generator.yaml diff --git a/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/policy-generator.yaml b/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/policy-generator.yaml new file mode 100755 index 0000000..e6df871 --- /dev/null +++ b/plugins_public/tests/data/ocm/deliverable-policy/policy-high-scan/policy-generator.yaml @@ -0,0 +1,31 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: PolicyGenerator +metadata: + name: policy-generator +policies: +- consolidateManifests: false + manifests: + - complianceType: musthave + path: ./compliance-high-scan + remediationAction: inform + severity: high + - complianceType: musthave + path: ./compliance-suite-high + remediationAction: inform + severity: high + - complianceType: mustnothave + path: ./compliance-suite-high-results + remediationAction: inform + severity: high + name: policy-high-scan + orderManifests: false +policyDefaults: + categories: [] + consolidateManifests: false + controls: [] + namespace: c2p + orderManifests: false + placement: + clusterSelectors: + environment: dev + standards: [] diff --git a/plugins_public/tests/data/ocm/placementdecisions.cluster.open-cluster-management.io.yaml b/plugins_public/tests/data/ocm/placementdecisions.cluster.open-cluster-management.io.yaml new file mode 100644 index 0000000..1175676 --- /dev/null +++ b/plugins_public/tests/data/ocm/placementdecisions.cluster.open-cluster-management.io.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +items: +- apiVersion: cluster.open-cluster-management.io/v1beta1 + kind: PlacementDecision + metadata: + creationTimestamp: "2023-07-05T16:10:56Z" + generation: 1 + labels: + cluster.open-cluster-management.io/placement: placement-managed-kubernetes + name: placement-managed-kubernetes-decision-1 + namespace: c2p + ownerReferences: + - apiVersion: cluster.open-cluster-management.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: Placement + name: placement-managed-kubernetes + uid: fb698906-ffbc-4483-afc1-e87cd6048858 + resourceVersion: "127345" + uid: 78e9e593-8ca7-48f2-86af-0306238cdedc + status: + decisions: + - clusterName: cluster1 + reason: "" + - clusterName: cluster2 + reason: "" +kind: List +metadata: + resourceVersion: "" diff --git a/plugins_public/tests/data/ocm/policies.policy.open-cluster-management.io.yaml b/plugins_public/tests/data/ocm/policies.policy.open-cluster-management.io.yaml new file mode 100644 index 0000000..b822566 --- /dev/null +++ b/plugins_public/tests/data/ocm/policies.policy.open-cluster-management.io.yaml @@ -0,0 +1,901 @@ +apiVersion: v1 +items: +- apiVersion: policy.open-cluster-management.io/v1 + kind: Policy + metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"policy.open-cluster-management.io/v1","kind":"Policy","metadata":{"annotations":{"policy.open-cluster-management.io/categories":"","policy.open-cluster-management.io/controls":"cm-2","policy.open-cluster-management.io/standards":""},"name":"policy-deployment","namespace":"c2p"},"spec":{"disabled":false,"policy-templates":[{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-deployment"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"musthave","objectDefinition":{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"labels":{"app":"nginx"},"name":"nginx-deployment"},"spec":{"replicas":3,"selector":{"matchLabels":{"app":"nginx"}},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"image":"nginx:1.21.4","name":"nginx","ports":[{"containerPort":80}]}]}}}}}],"remediationAction":"inform","severity":"low"}}}],"remediationAction":"inform"}} + policy.open-cluster-management.io/categories: "" + policy.open-cluster-management.io/controls: cm-2 + policy.open-cluster-management.io/standards: "" + creationTimestamp: "2023-07-05T16:10:56Z" + generation: 2 + name: policy-deployment + namespace: c2p + resourceVersion: "58942" + uid: 55fb6d11-cdf5-43a6-8848-7076ea3c02ba + spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-deployment + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app: nginx + name: nginx-deployment + spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx:1.21.4 + name: nginx + ports: + - containerPort: 80 + remediationAction: inform + severity: low + remediationAction: inform + status: + compliant: NonCompliant + placement: + - placement: placement-managed-kubernetes + placementBinding: policy-set + policySet: managed-kubernetes + status: + - clustername: cluster1 + clusternamespace: cluster1 + compliant: NonCompliant + - clustername: cluster2 + clusternamespace: cluster2 + compliant: NonCompliant +- apiVersion: policy.open-cluster-management.io/v1 + kind: Policy + metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"policy.open-cluster-management.io/v1","kind":"Policy","metadata":{"annotations":{"policy.open-cluster-management.io/categories":"","policy.open-cluster-management.io/controls":"ac-6","policy.open-cluster-management.io/standards":""},"name":"policy-disallowed-roles","namespace":"c2p"},"spec":{"disabled":false,"policy-templates":[{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-disallowed-roles"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"mustnothave","objectDefinition":{"apiVersion":"rbac.authorization.k8s.io/v1","kind":"Role","rules":[{"apiGroups":["*"],"resources":["*"],"verbs":["*"]}]}}],"remediationAction":"inform","severity":"high"}}}],"remediationAction":"inform"}} + policy.open-cluster-management.io/categories: "" + policy.open-cluster-management.io/controls: ac-6 + policy.open-cluster-management.io/standards: "" + creationTimestamp: "2023-07-05T16:10:56Z" + generation: 2 + name: policy-disallowed-roles + namespace: c2p + resourceVersion: "58945" + uid: 3aa8b4b0-6aa0-4635-a55d-342a9f38660e + spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-disallowed-roles + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + rules: + - apiGroups: + - '*' + resources: + - '*' + verbs: + - '*' + remediationAction: inform + severity: high + remediationAction: inform + status: + compliant: Compliant + placement: + - placement: placement-managed-kubernetes + placementBinding: policy-set + policySet: managed-kubernetes + status: + - clustername: cluster1 + clusternamespace: cluster1 + compliant: Compliant + - clustername: cluster2 + clusternamespace: cluster2 + compliant: Compliant +- apiVersion: policy.open-cluster-management.io/v1 + kind: Policy + metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"policy.open-cluster-management.io/v1","kind":"Policy","metadata":{"annotations":{"policy.open-cluster-management.io/categories":"","policy.open-cluster-management.io/controls":"cm-6","policy.open-cluster-management.io/standards":""},"name":"policy-high-scan","namespace":"c2p"},"spec":{"disabled":false,"policy-templates":[{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-high-scan"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"musthave","objectDefinition":{"apiVersion":"compliance.openshift.io/v1alpha1","kind":"ScanSettingBinding","metadata":{"name":"high","namespace":"openshift-compliance"},"profiles":[{"apiGroup":"compliance.openshift.io/v1alpha1","kind":"Profile","name":"ocp4-high"},{"apiGroup":"compliance.openshift.io/v1alpha1","kind":"Profile","name":"ocp4-high-node"}],"settingsRef":{"apiGroup":"compliance.openshift.io/v1alpha1","kind":"ScanSetting","name":"default"}}}],"remediationAction":"inform","severity":"high"}}},{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-high-scan2"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"musthave","objectDefinition":{"apiVersion":"compliance.openshift.io/v1alpha1","kind":"ComplianceSuite","metadata":{"name":"high","namespace":"openshift-compliance"},"status":{"phase":"DONE"}}}],"remediationAction":"inform","severity":"high"}}},{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-high-scan3"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"mustnothave","objectDefinition":{"apiVersion":"compliance.openshift.io/v1alpha1","kind":"ComplianceCheckResult","metadata":{"labels":{"compliance.openshift.io/check-status":"FAIL","compliance.openshift.io/suite":"high"},"namespace":"openshift-compliance"}}}],"remediationAction":"inform","severity":"high"}}}],"remediationAction":"inform"}} + policy.open-cluster-management.io/categories: "" + policy.open-cluster-management.io/controls: cm-6 + policy.open-cluster-management.io/standards: "" + creationTimestamp: "2023-07-05T16:10:56Z" + generation: 2 + name: policy-high-scan + namespace: c2p + resourceVersion: "58952" + uid: 1e829f28-a2e6-4b5b-9b58-d18c11730841 + spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-high-scan + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: compliance.openshift.io/v1alpha1 + kind: ScanSettingBinding + metadata: + name: high + namespace: openshift-compliance + profiles: + - apiGroup: compliance.openshift.io/v1alpha1 + kind: Profile + name: ocp4-high + - apiGroup: compliance.openshift.io/v1alpha1 + kind: Profile + name: ocp4-high-node + settingsRef: + apiGroup: compliance.openshift.io/v1alpha1 + kind: ScanSetting + name: default + remediationAction: inform + severity: high + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-high-scan2 + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: compliance.openshift.io/v1alpha1 + kind: ComplianceSuite + metadata: + name: high + namespace: openshift-compliance + status: + phase: DONE + remediationAction: inform + severity: high + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-high-scan3 + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: compliance.openshift.io/v1alpha1 + kind: ComplianceCheckResult + metadata: + labels: + compliance.openshift.io/check-status: FAIL + compliance.openshift.io/suite: high + namespace: openshift-compliance + remediationAction: inform + severity: high + remediationAction: inform + status: + compliant: NonCompliant + placement: + - placement: placement-managed-kubernetes + placementBinding: policy-set + policySet: managed-kubernetes + status: + - clustername: cluster1 + clusternamespace: cluster1 + compliant: NonCompliant + - clustername: cluster2 + clusternamespace: cluster2 + compliant: NonCompliant +- apiVersion: policy.open-cluster-management.io/v1 + kind: Policy + metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"policy.open-cluster-management.io/v1","kind":"Policy","metadata":{"annotations":{"policy.open-cluster-management.io/categories":"","policy.open-cluster-management.io/controls":"cm-2","policy.open-cluster-management.io/standards":""},"name":"policy-deployment","namespace":"c2p"},"spec":{"disabled":false,"policy-templates":[{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-deployment"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"musthave","objectDefinition":{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"labels":{"app":"nginx"},"name":"nginx-deployment"},"spec":{"replicas":3,"selector":{"matchLabels":{"app":"nginx"}},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"image":"nginx:1.21.4","name":"nginx","ports":[{"containerPort":80}]}]}}}}}],"remediationAction":"inform","severity":"low"}}}],"remediationAction":"inform"}} + policy.open-cluster-management.io/categories: "" + policy.open-cluster-management.io/controls: cm-2 + policy.open-cluster-management.io/standards: "" + creationTimestamp: "2023-07-05T23:52:32Z" + generation: 1 + labels: + policy.open-cluster-management.io/cluster-name: cluster1 + policy.open-cluster-management.io/cluster-namespace: cluster1 + policy.open-cluster-management.io/root-policy: c2p.policy-deployment + name: c2p.policy-deployment + namespace: cluster1 + resourceVersion: "58997" + uid: 3d7bf6b3-4332-4195-81b4-d343a847c3f8 + spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-deployment + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app: nginx + name: nginx-deployment + spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx:1.21.4 + name: nginx + ports: + - containerPort: 80 + remediationAction: inform + severity: low + remediationAction: inform + status: + compliant: NonCompliant + details: + - compliant: NonCompliant + history: + - eventName: c2p.policy-deployment.176f1ddc5591cb1c + lastTimestamp: "2023-07-05T23:53:37Z" + message: 'NonCompliant; violation - deployments not found: [nginx-deployment] + in namespace cluster1 missing; [nginx-deployment] in namespace kube-node-lease + missing; [nginx-deployment] in namespace kube-public missing; [nginx-deployment] + in namespace local-path-storage missing' + - eventName: c2p.policy-deployment.176f1dc090333b1b + lastTimestamp: "2023-07-05T23:51:38Z" + message: 'NonCompliant; violation - deployments not found: [nginx-deployment] + in namespace cluster1 missing; [nginx-deployment] in namespace kube-node-lease + missing; [nginx-deployment] in namespace kube-public missing; [nginx-deployment] + in namespace local-path-storage missing' + - eventName: c2p.policy-deployment.176f1bee3daf20de + lastTimestamp: "2023-07-05T23:18:15Z" + message: 'NonCompliant; violation - deployments not found: [nginx-deployment] + in namespace cluster1 missing; [nginx-deployment] in namespace kube-node-lease + missing; [nginx-deployment] in namespace kube-public missing; [nginx-deployment] + in namespace local-path-storage missing' + templateMeta: + creationTimestamp: null + name: policy-deployment +- apiVersion: policy.open-cluster-management.io/v1 + kind: Policy + metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"policy.open-cluster-management.io/v1","kind":"Policy","metadata":{"annotations":{"policy.open-cluster-management.io/categories":"","policy.open-cluster-management.io/controls":"ac-6","policy.open-cluster-management.io/standards":""},"name":"policy-disallowed-roles","namespace":"c2p"},"spec":{"disabled":false,"policy-templates":[{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-disallowed-roles"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"mustnothave","objectDefinition":{"apiVersion":"rbac.authorization.k8s.io/v1","kind":"Role","rules":[{"apiGroups":["*"],"resources":["*"],"verbs":["*"]}]}}],"remediationAction":"inform","severity":"high"}}}],"remediationAction":"inform"}} + policy.open-cluster-management.io/categories: "" + policy.open-cluster-management.io/controls: ac-6 + policy.open-cluster-management.io/standards: "" + creationTimestamp: "2023-07-05T23:52:32Z" + generation: 1 + labels: + policy.open-cluster-management.io/cluster-name: cluster1 + policy.open-cluster-management.io/cluster-namespace: cluster1 + policy.open-cluster-management.io/root-policy: c2p.policy-disallowed-roles + name: c2p.policy-disallowed-roles + namespace: cluster1 + resourceVersion: "58962" + uid: dea67078-25f4-4c45-9e55-01796af1999e + spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-disallowed-roles + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + rules: + - apiGroups: + - '*' + resources: + - '*' + verbs: + - '*' + remediationAction: inform + severity: high + remediationAction: inform + status: + compliant: Compliant + details: + - compliant: Compliant + history: + - eventName: c2p.policy-disallowed-roles.176f1dcdc4c8d17e + lastTimestamp: "2023-07-05T23:52:34Z" + message: Compliant; notification - roles in namespace cluster1; in namespace + default; in namespace kube-node-lease; in namespace kube-public; in namespace + local-path-storage missing as expected, therefore this Object template is + compliant + - eventName: c2p.policy-disallowed-roles.176f1cd7a1623786 + lastTimestamp: "2023-07-05T23:34:57Z" + message: Compliant; notification - roles in namespace cluster1; in namespace + default; in namespace kube-node-lease; in namespace kube-public; in namespace + local-path-storage missing as expected, therefore this Object template is + compliant + - eventName: c2p.policy-disallowed-roles.176f1bee3d61b1f3 + lastTimestamp: "2023-07-05T23:18:15Z" + message: Compliant; notification - roles in namespace cluster1; in namespace + default; in namespace kube-node-lease; in namespace kube-public; in namespace + local-path-storage missing as expected, therefore this Object template is + compliant + templateMeta: + creationTimestamp: null + name: policy-disallowed-roles +- apiVersion: policy.open-cluster-management.io/v1 + kind: Policy + metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"policy.open-cluster-management.io/v1","kind":"Policy","metadata":{"annotations":{"policy.open-cluster-management.io/categories":"","policy.open-cluster-management.io/controls":"cm-6","policy.open-cluster-management.io/standards":""},"name":"policy-high-scan","namespace":"c2p"},"spec":{"disabled":false,"policy-templates":[{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-high-scan"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"musthave","objectDefinition":{"apiVersion":"compliance.openshift.io/v1alpha1","kind":"ScanSettingBinding","metadata":{"name":"high","namespace":"openshift-compliance"},"profiles":[{"apiGroup":"compliance.openshift.io/v1alpha1","kind":"Profile","name":"ocp4-high"},{"apiGroup":"compliance.openshift.io/v1alpha1","kind":"Profile","name":"ocp4-high-node"}],"settingsRef":{"apiGroup":"compliance.openshift.io/v1alpha1","kind":"ScanSetting","name":"default"}}}],"remediationAction":"inform","severity":"high"}}},{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-high-scan2"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"musthave","objectDefinition":{"apiVersion":"compliance.openshift.io/v1alpha1","kind":"ComplianceSuite","metadata":{"name":"high","namespace":"openshift-compliance"},"status":{"phase":"DONE"}}}],"remediationAction":"inform","severity":"high"}}},{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-high-scan3"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"mustnothave","objectDefinition":{"apiVersion":"compliance.openshift.io/v1alpha1","kind":"ComplianceCheckResult","metadata":{"labels":{"compliance.openshift.io/check-status":"FAIL","compliance.openshift.io/suite":"high"},"namespace":"openshift-compliance"}}}],"remediationAction":"inform","severity":"high"}}}],"remediationAction":"inform"}} + policy.open-cluster-management.io/categories: "" + policy.open-cluster-management.io/controls: cm-6 + policy.open-cluster-management.io/standards: "" + creationTimestamp: "2023-07-05T23:52:32Z" + generation: 1 + labels: + policy.open-cluster-management.io/cluster-name: cluster1 + policy.open-cluster-management.io/cluster-namespace: cluster1 + policy.open-cluster-management.io/root-policy: c2p.policy-high-scan + name: c2p.policy-high-scan + namespace: cluster1 + resourceVersion: "58991" + uid: 4007f281-2977-42c4-ab42-cf0fb8563f56 + spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-high-scan + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: compliance.openshift.io/v1alpha1 + kind: ScanSettingBinding + metadata: + name: high + namespace: openshift-compliance + profiles: + - apiGroup: compliance.openshift.io/v1alpha1 + kind: Profile + name: ocp4-high + - apiGroup: compliance.openshift.io/v1alpha1 + kind: Profile + name: ocp4-high-node + settingsRef: + apiGroup: compliance.openshift.io/v1alpha1 + kind: ScanSetting + name: default + remediationAction: inform + severity: high + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-high-scan2 + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: compliance.openshift.io/v1alpha1 + kind: ComplianceSuite + metadata: + name: high + namespace: openshift-compliance + status: + phase: DONE + remediationAction: inform + severity: high + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-high-scan3 + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: compliance.openshift.io/v1alpha1 + kind: ComplianceCheckResult + metadata: + labels: + compliance.openshift.io/check-status: FAIL + compliance.openshift.io/suite: high + namespace: openshift-compliance + remediationAction: inform + severity: high + remediationAction: inform + status: + compliant: NonCompliant + details: + - compliant: NonCompliant + history: + - eventName: c2p.policy-high-scan.176f1dcdc2b51b01 + lastTimestamp: "2023-07-05T23:52:34Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ScanSettingBinding, please check if you have CRD deployed + - eventName: c2p.policy-high-scan.176f1cd79ed5ce45 + lastTimestamp: "2023-07-05T23:34:57Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ScanSettingBinding, please check if you have CRD deployed + - eventName: c2p.policy-high-scan.176f1bef5d9a8c7c + lastTimestamp: "2023-07-05T23:18:20Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ScanSettingBinding, please check if you have CRD deployed + templateMeta: + creationTimestamp: null + name: policy-high-scan + - compliant: NonCompliant + history: + - eventName: c2p.policy-high-scan.176f1ddc44adf035 + lastTimestamp: "2023-07-05T23:53:37Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ComplianceSuite, please check if you have CRD deployed + - eventName: c2p.policy-high-scan.176f1dc08583a394 + lastTimestamp: "2023-07-05T23:51:37Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ComplianceSuite, please check if you have CRD deployed + - eventName: c2p.policy-high-scan.176f1bef5e40c973 + lastTimestamp: "2023-07-05T23:18:20Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ComplianceSuite, please check if you have CRD deployed + templateMeta: + creationTimestamp: null + name: policy-high-scan2 + - compliant: NonCompliant + history: + - eventName: c2p.policy-high-scan.176f1ddc441457e5 + lastTimestamp: "2023-07-05T23:53:37Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ComplianceCheckResult, please check if you have CRD deployed + - eventName: c2p.policy-high-scan.176f1dc085241b09 + lastTimestamp: "2023-07-05T23:51:37Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ComplianceCheckResult, please check if you have CRD deployed + - eventName: c2p.policy-high-scan.176f1bf01c04e351 + lastTimestamp: "2023-07-05T23:18:23Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ComplianceCheckResult, please check if you have CRD deployed + templateMeta: + creationTimestamp: null + name: policy-high-scan3 +- apiVersion: policy.open-cluster-management.io/v1 + kind: Policy + metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"policy.open-cluster-management.io/v1","kind":"Policy","metadata":{"annotations":{"policy.open-cluster-management.io/categories":"","policy.open-cluster-management.io/controls":"cm-2","policy.open-cluster-management.io/standards":""},"name":"policy-deployment","namespace":"c2p"},"spec":{"disabled":false,"policy-templates":[{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-deployment"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"musthave","objectDefinition":{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"labels":{"app":"nginx"},"name":"nginx-deployment"},"spec":{"replicas":3,"selector":{"matchLabels":{"app":"nginx"}},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"image":"nginx:1.21.4","name":"nginx","ports":[{"containerPort":80}]}]}}}}}],"remediationAction":"inform","severity":"low"}}}],"remediationAction":"inform"}} + policy.open-cluster-management.io/categories: "" + policy.open-cluster-management.io/controls: cm-2 + policy.open-cluster-management.io/standards: "" + creationTimestamp: "2023-07-05T23:51:43Z" + generation: 1 + labels: + policy.open-cluster-management.io/cluster-name: cluster2 + policy.open-cluster-management.io/cluster-namespace: cluster2 + policy.open-cluster-management.io/root-policy: c2p.policy-deployment + name: c2p.policy-deployment + namespace: cluster2 + resourceVersion: "58322" + uid: 25080d0e-e6cf-4f39-94cb-04a7d01d6cfe + spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-deployment + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app: nginx + name: nginx-deployment + spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx:1.21.4 + name: nginx + ports: + - containerPort: 80 + remediationAction: inform + severity: low + remediationAction: inform + status: + compliant: NonCompliant + details: + - compliant: NonCompliant + history: + - eventName: c2p.policy-deployment.176f1dc4e7de17cb + lastTimestamp: "2023-07-05T23:51:56Z" + message: 'NonCompliant; violation - deployments not found: [nginx-deployment] + in namespace cluster2 missing; [nginx-deployment] in namespace default missing; + [nginx-deployment] in namespace kube-node-lease missing; [nginx-deployment] + in namespace kube-public missing; [nginx-deployment] in namespace local-path-storage + missing' + - eventName: c2p.policy-deployment.176f1bf28b594e3c + lastTimestamp: "2023-07-05T23:18:33Z" + message: 'NonCompliant; violation - deployments not found: [nginx-deployment] + in namespace cluster2 missing; [nginx-deployment] in namespace default missing; + [nginx-deployment] in namespace kube-node-lease missing; [nginx-deployment] + in namespace kube-public missing; [nginx-deployment] in namespace local-path-storage + missing' + - eventName: c2p.policy-deployment.176f1bf06f3be6c5 + lastTimestamp: "2023-07-05T23:18:24Z" + message: 'NonCompliant; violation - deployments not found: [nginx-deployment] + in namespace cluster2 missing; [nginx-deployment] in namespace default missing; + [nginx-deployment] in namespace kube-node-lease missing; [nginx-deployment] + in namespace kube-public missing; [nginx-deployment] in namespace local-path-storage + missing' + templateMeta: + creationTimestamp: null + name: policy-deployment +- apiVersion: policy.open-cluster-management.io/v1 + kind: Policy + metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"policy.open-cluster-management.io/v1","kind":"Policy","metadata":{"annotations":{"policy.open-cluster-management.io/categories":"","policy.open-cluster-management.io/controls":"ac-6","policy.open-cluster-management.io/standards":""},"name":"policy-disallowed-roles","namespace":"c2p"},"spec":{"disabled":false,"policy-templates":[{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-disallowed-roles"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"mustnothave","objectDefinition":{"apiVersion":"rbac.authorization.k8s.io/v1","kind":"Role","rules":[{"apiGroups":["*"],"resources":["*"],"verbs":["*"]}]}}],"remediationAction":"inform","severity":"high"}}}],"remediationAction":"inform"}} + policy.open-cluster-management.io/categories: "" + policy.open-cluster-management.io/controls: ac-6 + policy.open-cluster-management.io/standards: "" + creationTimestamp: "2023-07-05T23:51:43Z" + generation: 1 + labels: + policy.open-cluster-management.io/cluster-name: cluster2 + policy.open-cluster-management.io/cluster-namespace: cluster2 + policy.open-cluster-management.io/root-policy: c2p.policy-disallowed-roles + name: c2p.policy-disallowed-roles + namespace: cluster2 + resourceVersion: "58171" + uid: fb2bed28-f7be-4ad3-9df2-00f26600feb7 + spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-disallowed-roles + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + rules: + - apiGroups: + - '*' + resources: + - '*' + verbs: + - '*' + remediationAction: inform + severity: high + remediationAction: inform + status: + compliant: Compliant + details: + - compliant: Compliant + history: + - eventName: c2p.policy-disallowed-roles.176f1dc36e36b7b2 + lastTimestamp: "2023-07-05T23:51:50Z" + message: Compliant; notification - roles in namespace cluster2; in namespace + default; in namespace kube-node-lease; in namespace kube-public; in namespace + local-path-storage missing as expected, therefore this Object template is + compliant + - eventName: c2p.policy-disallowed-roles.176f1bf28b48947f + lastTimestamp: "2023-07-05T23:18:33Z" + message: Compliant; notification - roles in namespace cluster2; in namespace + default; in namespace kube-node-lease; in namespace kube-public; in namespace + local-path-storage missing as expected, therefore this Object template is + compliant + templateMeta: + creationTimestamp: null + name: policy-disallowed-roles +- apiVersion: policy.open-cluster-management.io/v1 + kind: Policy + metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"policy.open-cluster-management.io/v1","kind":"Policy","metadata":{"annotations":{"policy.open-cluster-management.io/categories":"","policy.open-cluster-management.io/controls":"cm-6","policy.open-cluster-management.io/standards":""},"name":"policy-high-scan","namespace":"c2p"},"spec":{"disabled":false,"policy-templates":[{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-high-scan"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"musthave","objectDefinition":{"apiVersion":"compliance.openshift.io/v1alpha1","kind":"ScanSettingBinding","metadata":{"name":"high","namespace":"openshift-compliance"},"profiles":[{"apiGroup":"compliance.openshift.io/v1alpha1","kind":"Profile","name":"ocp4-high"},{"apiGroup":"compliance.openshift.io/v1alpha1","kind":"Profile","name":"ocp4-high-node"}],"settingsRef":{"apiGroup":"compliance.openshift.io/v1alpha1","kind":"ScanSetting","name":"default"}}}],"remediationAction":"inform","severity":"high"}}},{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-high-scan2"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"musthave","objectDefinition":{"apiVersion":"compliance.openshift.io/v1alpha1","kind":"ComplianceSuite","metadata":{"name":"high","namespace":"openshift-compliance"},"status":{"phase":"DONE"}}}],"remediationAction":"inform","severity":"high"}}},{"objectDefinition":{"apiVersion":"policy.open-cluster-management.io/v1","kind":"ConfigurationPolicy","metadata":{"name":"policy-high-scan3"},"spec":{"namespaceSelector":{"exclude":["kube-system","open-cluster-management","open-cluster-management-agent","open-cluster-management-agent-addon"],"include":["*"]},"object-templates":[{"complianceType":"mustnothave","objectDefinition":{"apiVersion":"compliance.openshift.io/v1alpha1","kind":"ComplianceCheckResult","metadata":{"labels":{"compliance.openshift.io/check-status":"FAIL","compliance.openshift.io/suite":"high"},"namespace":"openshift-compliance"}}}],"remediationAction":"inform","severity":"high"}}}],"remediationAction":"inform"}} + policy.open-cluster-management.io/categories: "" + policy.open-cluster-management.io/controls: cm-6 + policy.open-cluster-management.io/standards: "" + creationTimestamp: "2023-07-05T23:51:43Z" + generation: 1 + labels: + policy.open-cluster-management.io/cluster-name: cluster2 + policy.open-cluster-management.io/cluster-namespace: cluster2 + policy.open-cluster-management.io/root-policy: c2p.policy-high-scan + name: c2p.policy-high-scan + namespace: cluster2 + resourceVersion: "58319" + uid: 38eb6af4-5b3f-4a8b-aa1b-f066cd7a3ed8 + spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-high-scan + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: compliance.openshift.io/v1alpha1 + kind: ScanSettingBinding + metadata: + name: high + namespace: openshift-compliance + profiles: + - apiGroup: compliance.openshift.io/v1alpha1 + kind: Profile + name: ocp4-high + - apiGroup: compliance.openshift.io/v1alpha1 + kind: Profile + name: ocp4-high-node + settingsRef: + apiGroup: compliance.openshift.io/v1alpha1 + kind: ScanSetting + name: default + remediationAction: inform + severity: high + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-high-scan2 + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: compliance.openshift.io/v1alpha1 + kind: ComplianceSuite + metadata: + name: high + namespace: openshift-compliance + status: + phase: DONE + remediationAction: inform + severity: high + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-high-scan3 + spec: + namespaceSelector: + exclude: + - kube-system + - open-cluster-management + - open-cluster-management-agent + - open-cluster-management-agent-addon + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: compliance.openshift.io/v1alpha1 + kind: ComplianceCheckResult + metadata: + labels: + compliance.openshift.io/check-status: FAIL + compliance.openshift.io/suite: high + namespace: openshift-compliance + remediationAction: inform + severity: high + remediationAction: inform + status: + compliant: NonCompliant + details: + - compliant: NonCompliant + history: + - eventName: c2p.policy-high-scan.176f1dc3684f9eb6 + lastTimestamp: "2023-07-05T23:51:50Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ScanSettingBinding, please check if you have CRD deployed + - eventName: c2p.policy-high-scan.176f1ccd9a7768a0 + lastTimestamp: "2023-07-05T23:34:14Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ScanSettingBinding, please check if you have CRD deployed + templateMeta: + creationTimestamp: null + name: policy-high-scan + - compliant: NonCompliant + history: + - eventName: c2p.policy-high-scan.176f1dc426d20948 + lastTimestamp: "2023-07-05T23:51:53Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ComplianceSuite, please check if you have CRD deployed + - eventName: c2p.policy-high-scan.176f1ccd9a7af3da + lastTimestamp: "2023-07-05T23:34:14Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ComplianceSuite, please check if you have CRD deployed + templateMeta: + creationTimestamp: null + name: policy-high-scan2 + - compliant: NonCompliant + history: + - eventName: c2p.policy-high-scan.176f1dc4e29e1221 + lastTimestamp: "2023-07-05T23:51:56Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ComplianceCheckResult, please check if you have CRD deployed + - eventName: c2p.policy-high-scan.176f1cce592bc71e + lastTimestamp: "2023-07-05T23:34:17Z" + message: NonCompliant; violation - couldn't find mapping resource with kind + ComplianceCheckResult, please check if you have CRD deployed + templateMeta: + creationTimestamp: null + name: policy-high-scan3 +kind: List +metadata: + resourceVersion: "" diff --git a/plugins_public/tests/data/ocm/policy-resources/policy-deployment/kustomization.yaml b/plugins_public/tests/data/ocm/policy-resources/policy-deployment/kustomization.yaml new file mode 100755 index 0000000..0573618 --- /dev/null +++ b/plugins_public/tests/data/ocm/policy-resources/policy-deployment/kustomization.yaml @@ -0,0 +1,2 @@ +generators: +- ./policy-generator.yaml diff --git a/plugins_public/tests/data/ocm/policy-resources/policy-deployment/policy-generator.yaml b/plugins_public/tests/data/ocm/policy-resources/policy-deployment/policy-generator.yaml new file mode 100755 index 0000000..a862b0e --- /dev/null +++ b/plugins_public/tests/data/ocm/policy-resources/policy-deployment/policy-generator.yaml @@ -0,0 +1,17 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: PolicyGenerator +metadata: + name: policy-generator +policyDefaults: + consolidateManifests: false + orderManifests: false + namespace: namespace +policies: + - consolidateManifests: true + orderManifests: false + remediationAction: inform + severity: low + complianceType: musthave + name: policy-deployment + manifests: + - path: ./policy-nginx-deployment diff --git a/plugins_public/tests/data/ocm/policy-resources/policy-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml b/plugins_public/tests/data/ocm/policy-resources/policy-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml new file mode 100755 index 0000000..8d59ace --- /dev/null +++ b/plugins_public/tests/data/ocm/policy-resources/policy-deployment/policy-nginx-deployment/Deployment.nginx-deployment.0.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + replicas: '{{hub fromConfigMap "c2p" "c2p-parameters" "minimum_nginx_deployment_replicas" | toInt hub}}' + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx:1.21.4 + name: nginx + ports: + - containerPort: 80 diff --git a/plugins_public/tests/data/ocm/policy-resources/policy-disallowed-roles/kustomization.yaml b/plugins_public/tests/data/ocm/policy-resources/policy-disallowed-roles/kustomization.yaml new file mode 100755 index 0000000..0573618 --- /dev/null +++ b/plugins_public/tests/data/ocm/policy-resources/policy-disallowed-roles/kustomization.yaml @@ -0,0 +1,2 @@ +generators: +- ./policy-generator.yaml diff --git a/plugins_public/tests/data/ocm/policy-resources/policy-disallowed-roles/policy-disallowed-roles-sample-role/Role.noname.0.yaml b/plugins_public/tests/data/ocm/policy-resources/policy-disallowed-roles/policy-disallowed-roles-sample-role/Role.noname.0.yaml new file mode 100755 index 0000000..bb259be --- /dev/null +++ b/plugins_public/tests/data/ocm/policy-resources/policy-disallowed-roles/policy-disallowed-roles-sample-role/Role.noname.0.yaml @@ -0,0 +1,9 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +rules: +- apiGroups: + - '*' + resources: + - '*' + verbs: + - '*' diff --git a/plugins_public/tests/data/ocm/policy-resources/policy-disallowed-roles/policy-generator.yaml b/plugins_public/tests/data/ocm/policy-resources/policy-disallowed-roles/policy-generator.yaml new file mode 100755 index 0000000..b3ef68e --- /dev/null +++ b/plugins_public/tests/data/ocm/policy-resources/policy-disallowed-roles/policy-generator.yaml @@ -0,0 +1,17 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: PolicyGenerator +metadata: + name: policy-generator +policyDefaults: + consolidateManifests: false + orderManifests: false + namespace: namespace +policies: + - consolidateManifests: true + orderManifests: false + remediationAction: inform + severity: high + complianceType: mustnothave + name: policy-disallowed-roles + manifests: + - path: ./policy-disallowed-roles-sample-role diff --git a/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/compliance-high-scan/ScanSettingBinding.high.0.yaml b/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/compliance-high-scan/ScanSettingBinding.high.0.yaml new file mode 100755 index 0000000..620bcd0 --- /dev/null +++ b/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/compliance-high-scan/ScanSettingBinding.high.0.yaml @@ -0,0 +1,16 @@ +apiVersion: compliance.openshift.io/v1alpha1 +kind: ScanSettingBinding +metadata: + name: high + namespace: openshift-compliance +profiles: +- apiGroup: compliance.openshift.io/v1alpha1 + kind: Profile + name: ocp4-high +- apiGroup: compliance.openshift.io/v1alpha1 + kind: Profile + name: ocp4-high-node +settingsRef: + apiGroup: compliance.openshift.io/v1alpha1 + kind: ScanSetting + name: default diff --git a/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/compliance-suite-high-results/ComplianceCheckResult.noname.0.yaml b/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/compliance-suite-high-results/ComplianceCheckResult.noname.0.yaml new file mode 100755 index 0000000..e1cba9b --- /dev/null +++ b/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/compliance-suite-high-results/ComplianceCheckResult.noname.0.yaml @@ -0,0 +1,7 @@ +apiVersion: compliance.openshift.io/v1alpha1 +kind: ComplianceCheckResult +metadata: + labels: + compliance.openshift.io/check-status: FAIL + compliance.openshift.io/suite: high + namespace: openshift-compliance diff --git a/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/compliance-suite-high/ComplianceSuite.high.0.yaml b/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/compliance-suite-high/ComplianceSuite.high.0.yaml new file mode 100755 index 0000000..cdc5b90 --- /dev/null +++ b/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/compliance-suite-high/ComplianceSuite.high.0.yaml @@ -0,0 +1,7 @@ +apiVersion: compliance.openshift.io/v1alpha1 +kind: ComplianceSuite +metadata: + name: high + namespace: openshift-compliance +status: + phase: DONE diff --git a/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/kustomization.yaml b/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/kustomization.yaml new file mode 100755 index 0000000..0573618 --- /dev/null +++ b/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/kustomization.yaml @@ -0,0 +1,2 @@ +generators: +- ./policy-generator.yaml diff --git a/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/policy-generator.yaml b/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/policy-generator.yaml new file mode 100755 index 0000000..3fad8fc --- /dev/null +++ b/plugins_public/tests/data/ocm/policy-resources/policy-high-scan/policy-generator.yaml @@ -0,0 +1,25 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: PolicyGenerator +metadata: + name: policy-generator +policyDefaults: + consolidateManifests: false + orderManifests: false + namespace: namespace +policies: + - consolidateManifests: false + orderManifests: false + name: policy-high-scan + manifests: + - remediationAction: inform + severity: high + complianceType: musthave + path: ./compliance-high-scan + - remediationAction: inform + severity: high + complianceType: musthave + path: ./compliance-suite-high + - remediationAction: inform + severity: high + complianceType: mustnothave + path: ./compliance-suite-high-results diff --git a/plugins_public/tests/data/ocm/policysets.policy.open-cluster-management.io.yaml b/plugins_public/tests/data/ocm/policysets.policy.open-cluster-management.io.yaml new file mode 100644 index 0000000..1c8acb0 --- /dev/null +++ b/plugins_public/tests/data/ocm/policysets.policy.open-cluster-management.io.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +items: +- apiVersion: policy.open-cluster-management.io/v1beta1 + kind: PolicySet + metadata: + annotations: + compliance-to-policy.component-title: Managed Kubernetes + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"policy.open-cluster-management.io/v1beta1","kind":"PolicySet","metadata":{"annotations":{"compliance-to-policy.component-title":"Managed Kubernetes"},"name":"managed-kubernetes","namespace":"c2p"},"spec":{"description":"","policies":["policy-deployment","policy-disallowed-roles","policy-high-scan"]}} + creationTimestamp: "2023-07-05T16:10:56Z" + generation: 1 + name: managed-kubernetes + namespace: c2p + resourceVersion: "80787" + uid: 1ac57f03-4782-4ef8-8b65-08384e36971f + spec: + description: "" + policies: + - policy-deployment + - policy-disallowed-roles + - policy-high-scan + status: + compliant: NonCompliant + placement: + - placement: placement-managed-kubernetes + placementBinding: policy-set + statusMessage: All policies are reporting status +kind: List +metadata: + resourceVersion: "" diff --git a/plugins_public/tests/plugins/__init__.py b/plugins_public/tests/plugins/__init__.py new file mode 100644 index 0000000..bd26775 --- /dev/null +++ b/plugins_public/tests/plugins/__init__.py @@ -0,0 +1,15 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/plugins_public/tests/plugins/test_kyverno.py b/plugins_public/tests/plugins/test_kyverno.py new file mode 100644 index 0000000..3871d92 --- /dev/null +++ b/plugins_public/tests/plugins/test_kyverno.py @@ -0,0 +1,76 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import pathlib + +from c2p.framework.models import Parameter, Policy, RawResult, RuleSet +from plugins_public.plugins.kyverno import PluginConfigKyverno, PluginKyverno +from plugins_public.tests.utils import load_yaml, load_yamls + +TEST_DATA_DIR = os.getenv('TEST_DATA_DIR', 'plugins_public/tests/data/kyverno') + + +def test_kyverno_pvp_result_to_compliance(): + cpolr = load_yaml(f'{TEST_DATA_DIR}/clusterpolicyreports.wgpolicyk8s.io.yaml') + polr = load_yaml(f'{TEST_DATA_DIR}/policyreports.wgpolicyk8s.io.yaml') + raw = cpolr['items'] + polr['items'] + raw_result = RawResult(data=raw) + pvp_result = PluginKyverno().generate_pvp_result(raw_result) + assert 2 == len(pvp_result.observations_by_check) + assert 33 == len(pvp_result.observations_by_check[0].subjects) + assert 33 == len(pvp_result.observations_by_check[1].subjects) + + +def test_kyverno_compliance_to_policy(): + policy_template_dir = f'{TEST_DATA_DIR}/policy-resources' + deliverable_policy_dir = f'{TEST_DATA_DIR}/deliverable-policy' + config = PluginConfigKyverno(policy_template_dir=policy_template_dir, deliverable_policy_dir=deliverable_policy_dir) + rule_sets = [ + RuleSet(rule_id='allowed-base-images', check_id=''), + RuleSet(rule_id='disallow-capabilities', check_id=''), + ] + parameters = [Parameter(id='allowed_baseimages', value='gcr.io/distroless/static:root')] + policy = Policy(rule_sets=rule_sets, parameters=parameters) + + PluginKyverno(config).generate_pvp_policy(policy) + + policy_template_dir = pathlib.Path(policy_template_dir) + deliverable_policy_dir = pathlib.Path(deliverable_policy_dir) + policy_dirs = filter(lambda x: x.is_dir(), deliverable_policy_dir.iterdir()) + assert set(['disallow-capabilities', 'allowed-base-images']) == set(map(lambda x: x.name, policy_dirs)) + + # disallow-capabilities + policy_dir = deliverable_policy_dir / 'disallow-capabilities' + assert set(['disallow-capabilities.yaml']) == set(map(lambda x: x.name, policy_dir.iterdir())) + + policy = load_yaml(policy_dir / 'disallow-capabilities.yaml') + expected = load_yaml(policy_template_dir / 'disallow-capabilities' / 'disallow-capabilities.yaml') + assert expected == policy + + # allowed-base-images + policy_dir = deliverable_policy_dir / 'allowed-base-images' + assert set(['allowed-base-images.yaml', '02-setup-cm.yaml']) == set(map(lambda x: x.name, policy_dir.iterdir())) + + setup_yaml_path = policy_dir / '02-setup-cm.yaml' + setup_yamls = load_yamls(setup_yaml_path) + configmap = next(filter(lambda x: x['kind'] == 'ConfigMap', setup_yamls), None) + assert 'gcr.io/distroless/static:root' == configmap['data']['allowedbaseimages'] + + policy_path = policy_dir / 'allowed-base-images.yaml' + policy = load_yaml(policy_path) + expected = load_yaml(policy_template_dir / 'allowed-base-images' / 'allowed-base-images.yaml') + assert expected == policy diff --git a/plugins_public/tests/plugins/test_ocm.py b/plugins_public/tests/plugins/test_ocm.py new file mode 100644 index 0000000..88f1964 --- /dev/null +++ b/plugins_public/tests/plugins/test_ocm.py @@ -0,0 +1,130 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import pathlib +import shutil +import tempfile +from distutils.util import strtobool + +from c2p.framework.models import Parameter, Policy, RawResult, RuleSet +from plugins_public.plugins.ocm import PluginConfigOCM, PluginOCM +from plugins_public.tests.utils import load_yaml + +TEST_DATA_DIR = os.getenv('TEST_DATA_DIR', 'plugins_public/tests/data/ocm') +OVERWRITE_EXPECTED_DATA = os.getenv('OVERWRITE_EXPECTED_DATA', 'false') +KEEP_TEMP_FILE_AND_DIR = os.getenv('KEEP_TEMP_FILE_AND_DIR', 'false') + + +def test_ocm_pvp_result_to_compliance(): + pds = load_yaml(f'{TEST_DATA_DIR}/placementdecisions.cluster.open-cluster-management.io.yaml') + policies = load_yaml(f'{TEST_DATA_DIR}/policies.policy.open-cluster-management.io.yaml') + policy_sets = load_yaml(f'{TEST_DATA_DIR}/policysets.policy.open-cluster-management.io.yaml') + raw = pds['items'] + policies['items'] + policy_sets['items'] + raw_result = RawResult(data=raw) + pvp_result = PluginOCM().generate_pvp_result(raw_result) + assert len(pvp_result.observations_by_check) == 3 + assert len(pvp_result.observations_by_check[0].subjects) == 2 + + +def test_ocm_compliance_to_policy(): + tmpdir = tempfile.mkdtemp() + policy_template_dir = pathlib.Path(f'{TEST_DATA_DIR}/policy-resources') + deliverable_policy_dir = pathlib.Path(f'{tmpdir}/deliverable-policy') + expected_deliverable_policy_dir = pathlib.Path(f'{TEST_DATA_DIR}/deliverable-policy') + config = PluginConfigOCM( + policy_template_dir=policy_template_dir.as_posix(), + deliverable_policy_dir=deliverable_policy_dir.as_posix(), + namespace='c2p', + paremeters_configmap_name='c2p-parameters', + cluster_selectors={'environment': 'dev'}, + policy_set_name='c2p test', + ) + rule_sets = [ + RuleSet(rule_id='policy-deployment', check_id=''), + RuleSet(rule_id='policy-disallowed-roles', check_id=''), + RuleSet(rule_id='policy-high-scan', check_id=''), + ] + parameters = [Parameter(id='minimum_nginx_deployment_replicas', value='3')] + policy = Policy(rule_sets=rule_sets, parameters=parameters) + + PluginOCM(config).generate_pvp_policy(policy) + + policy_dirs = filter(lambda x: x.is_dir(), deliverable_policy_dir.iterdir()) + assert set(['policy-disallowed-roles', 'policy-deployment', 'policy-high-scan']) == set( + map(lambda x: x.name, policy_dirs) + ) + assert set(['kustomization.yaml', 'parameters.yaml', 'policy-generator.yaml']) == set( + map(lambda x: x.name, filter(lambda x1: x1.is_file(), deliverable_policy_dir.iterdir())) + ) + + expected = load_yaml(expected_deliverable_policy_dir / 'policy-generator.yaml') + actual = load_yaml(deliverable_policy_dir / 'policy-generator.yaml') + assert expected == actual + + expected = load_yaml(expected_deliverable_policy_dir / 'kustomization.yaml') + actual = load_yaml(deliverable_policy_dir / 'kustomization.yaml') + assert expected == actual + + expected = load_yaml(expected_deliverable_policy_dir / 'policy-generator.yaml') + actual = load_yaml(deliverable_policy_dir / 'policy-generator.yaml') + assert expected == actual + + # policy-disallowed-roles + policy_dir = deliverable_policy_dir / 'policy-disallowed-roles' + assert set(['policy-disallowed-roles-sample-role', 'kustomization.yaml', 'policy-generator.yaml']) == set( + map(lambda x: x.name, policy_dir.iterdir()) + ) + assert set(['Role.noname.0.yaml']) == set( + map(lambda x: x.name, (policy_dir / 'policy-disallowed-roles-sample-role').iterdir()) + ) + + # policy-deployment + policy_dir = deliverable_policy_dir / 'policy-deployment' + assert set(['policy-nginx-deployment', 'kustomization.yaml', 'policy-generator.yaml']) == set( + map(lambda x: x.name, policy_dir.iterdir()) + ) + assert set(['Deployment.nginx-deployment.0.yaml']) == set( + map(lambda x: x.name, (policy_dir / 'policy-nginx-deployment').iterdir()) + ) + + # policy-high-scan + policy_dir = deliverable_policy_dir / 'policy-high-scan' + assert set( + [ + 'compliance-high-scan', + 'compliance-suite-high', + 'compliance-suite-high-results', + 'kustomization.yaml', + 'policy-generator.yaml', + ] + ) == set(map(lambda x: x.name, policy_dir.iterdir())) + assert set(['ScanSettingBinding.high.0.yaml']) == set( + map(lambda x: x.name, (policy_dir / 'compliance-high-scan').iterdir()) + ) + assert set(['ComplianceSuite.high.0.yaml']) == set( + map(lambda x: x.name, (policy_dir / 'compliance-suite-high').iterdir()) + ) + assert set(['ComplianceCheckResult.noname.0.yaml']) == set( + map(lambda x: x.name, (policy_dir / 'compliance-suite-high-results').iterdir()) + ) + + if strtobool(OVERWRITE_EXPECTED_DATA): + shutil.rmtree(expected_deliverable_policy_dir) + shutil.copytree(deliverable_policy_dir, expected_deliverable_policy_dir) + + if not strtobool(KEEP_TEMP_FILE_AND_DIR): + shutil.rmtree(tmpdir) diff --git a/plugins_public/tests/utils.py b/plugins_public/tests/utils.py new file mode 100644 index 0000000..4d4f356 --- /dev/null +++ b/plugins_public/tests/utils.py @@ -0,0 +1,32 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pathlib +from typing import Dict, Union, List + +import yaml + + +def load_yaml(path: Union[str, pathlib.Path]) -> Dict: + if isinstance(path, str): + path = pathlib.Path(path) + return yaml.safe_load(path.open('r')) + + +def load_yamls(path: Union[str, pathlib.Path]) -> List[Dict]: + if isinstance(path, str): + path = pathlib.Path(path) + return yaml.safe_load_all(path.open('r')) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..f883c03 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,95 @@ +[build-system] +requires = ["setuptools", "setuptools-git-versioning"] +build-backend = "setuptools.build_meta" + +[tool.setuptools-git-versioning] +enabled = true +count_commits_from_version_file = true +dev_template = "{tag}.post{ccount}+git.{sha}.dirty" +dirty_template = "{tag}.post{ccount}+git.{sha}.dirty" + +[tool.setuptools] +package-dir = { "c2p" = "c2p" } + +[tool.setuptools.packages.find] +include = ["c2p*"] + +[project] +dynamic = ["version"] +name = "compliance-to-policy" +authors = [{ name = "Takumi Yanagawa", email = "yana1205dev@gmail.com" }] +description = "Tools to bridge Compliance and Policy" +readme = "README.md" +license = { file = "LICENSE" } +requires-python = ">=3.9" +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", +] +dependencies = [ + "compliance-trestle==2.2.1", + "PyGithub==1.58.0", + "jq==1.6.0", + "pluggy", +] + +[project.scripts] +c2p = "c2p.cli:run" + +[project.optional-dependencies] +dev = [ + "build>=1.0.3", + "pyclean", + "pytest>=8.0.0", + "pre-commit>=2.4.0", + "pep8-naming", + "types-PyYAML", + "types-setuptools", + ## Docs website + "mkdocs", + "mkdocs-redirects", + "mkdocstrings-python", + ## Constrain system + "black", + "isort", + "pylint", + ## Security tools + "detect-secrets@git+https://github.com/ibm/detect-secrets.git@master#egg=detect-secrets" +] + +[project.urls] +Homepage = "https://github.com/oscal-compass/compliance-to-policy" +Issues = "https://github.com/oscal-compass/compliance-to-policy/issues" + +[tool.pytest.ini_options] +log_cli = true +log_cli_level = "INFO" +log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)" +log_cli_date_format = "%Y-%m-%d %H:%M:%S" +minversion = "6.0" +addopts = "-ra -q" +testpaths = ["tests", "plugins_public/tests"] +pythonpath = ["c2p", "plugins_public/tests"] + +[tool.isort] +profile = "black" +extend_skip_glob = "go" + +[tool.black] +line-length = 120 +skip-string-normalization = true +extend-exclude = "go" + +[tool.pylint.master] +ignore = "oscal" +extension-pkg-whitelist = "pydantic" + +[tool.pylint.messages_control] +disable = ["W1203", "W1201"] + +[tool.pylint.format] +max-line-length = 120 diff --git a/samples_public/__init__.py b/samples_public/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/samples_public/kyverno/compliance_to_policy.py b/samples_public/kyverno/compliance_to_policy.py new file mode 100644 index 0000000..4a42e95 --- /dev/null +++ b/samples_public/kyverno/compliance_to_policy.py @@ -0,0 +1,56 @@ +import argparse +import os +import pathlib +import sys +import tempfile + +from c2p.framework.c2p import C2P +from c2p.framework.models.c2p_config import C2PConfig, ComplianceOscal + +sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) +from plugins_public.plugins.kyverno import PluginConfigKyverno, PluginKyverno + +TEST_DATA_DIR = 'plugins_public/tests/data/kyverno' + +parser = argparse.ArgumentParser() +parser.add_argument( + '-o', '--out', type=str, help='Path to output directory (default: system temporary directory)', required=False +) +args = parser.parse_args() + +tmpdirname = args.out if args.out != None else tempfile.mkdtemp() + +# Setup c2p_config +c2p_config = C2PConfig() +c2p_config.compliance = ComplianceOscal() +c2p_config.compliance.component_definition = f'{TEST_DATA_DIR}/component-definition.json' +c2p_config.pvp_name = 'Kyverno' +c2p_config.result_title = 'Kyverno Assessment Results' +c2p_config.result_description = 'OSCAL Assessment Results from Kyverno' + +# Construct C2P +c2p = C2P(c2p_config) + +# Transform OSCAL (Compliance) to Policy +policy_template_dir = f'{TEST_DATA_DIR}/policy-resources' +config = PluginConfigKyverno(policy_template_dir=policy_template_dir, deliverable_policy_dir=tmpdirname) +PluginKyverno(config).generate_pvp_policy(c2p.get_policy()) + + +def tree(path: pathlib.Path, texts: list[str] = [], depth=0) -> list[str]: + prefix = '' + if depth > 0: + for _ in range(depth): + prefix = prefix + '-' + prefix = prefix + ' ' + for item in path.iterdir(): + texts.append(f'{prefix}{item.name}') + if item.is_dir(): + tree(item, texts, depth=depth + 1) + return texts + + +print('') +print(f'tree {tmpdirname}') +for text in tree(pathlib.Path(tmpdirname)): + print(text) diff --git a/samples_public/kyverno/result_to_compliance.py b/samples_public/kyverno/result_to_compliance.py new file mode 100644 index 0000000..6b145b3 --- /dev/null +++ b/samples_public/kyverno/result_to_compliance.py @@ -0,0 +1,58 @@ +import argparse +import os +import pathlib +import sys + +import yaml + +from c2p.framework.c2p import C2P +from c2p.framework.models import RawResult +from c2p.framework.models.c2p_config import C2PConfig, ComplianceOscal +from c2p.framework.models.raw_result import RawResult + +sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) +from plugins_public.plugins.kyverno import PluginKyverno + +TEST_DATA_DIR = 'plugins_public/tests/data/kyverno' + +parser = argparse.ArgumentParser() +parser.add_argument( + '-polr', + '--policy-report', + type=str, + default=f'{TEST_DATA_DIR}/policyreports.wgpolicyk8s.io.yaml', + help='Path to policy report', + required=False, +) +parser.add_argument( + '-cpolr', + '--cluster-policy-report', + type=str, + default=f'{TEST_DATA_DIR}/clusterpolicyreports.wgpolicyk8s.io.yaml', + help='Path to cluster policy report', + required=False, +) +args = parser.parse_args() + +# Setup c2p_config +c2p_config = C2PConfig() +c2p_config.compliance = ComplianceOscal() +c2p_config.compliance.component_definition = f'{TEST_DATA_DIR}/component-definition.json' +c2p_config.pvp_name = 'Kyverno' +c2p_config.result_title = 'Kyverno Assessment Results' +c2p_config.result_description = 'OSCAL Assessment Results from Kyverno' + +# Construct C2P +c2p = C2P(c2p_config) + +# Create pvp_result from raw result via plugin +cpolr = yaml.safe_load(pathlib.Path(args.cluster_policy_report).open('r')) +polr = yaml.safe_load(pathlib.Path(args.policy_report).open('r')) +pvp_raw_result = RawResult(data=cpolr['items'] + polr['items']) +pvp_result = PluginKyverno().generate_pvp_result(pvp_raw_result) + +# Transform pvp_result to OSCAL Assessment Result +c2p.set_pvp_result(pvp_result) +oscal_assessment_results = c2p.result_to_oscal() + +print(oscal_assessment_results.oscal_serialize_json(pretty=True)) diff --git a/samples_public/ocm/compliance_to_policy.py b/samples_public/ocm/compliance_to_policy.py new file mode 100644 index 0000000..88684fa --- /dev/null +++ b/samples_public/ocm/compliance_to_policy.py @@ -0,0 +1,61 @@ +import argparse +import os +import pathlib +import sys +import tempfile + +from c2p.framework.c2p import C2P +from c2p.framework.models.c2p_config import C2PConfig, ComplianceOscal + +sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) +from plugins_public.plugins.ocm import PluginOCM, PluginConfigOCM + +TEST_DATA_DIR = 'plugins_public/tests/data/ocm' + +parser = argparse.ArgumentParser() +parser.add_argument( + '-o', '--out', type=str, help='Path to output directory (default: system temporary directory)', required=False +) +args = parser.parse_args() + +tmpdirname = args.out if args.out != None else tempfile.mkdtemp() + +# Setup c2p_config +c2p_config = C2PConfig() +c2p_config.compliance = ComplianceOscal() +c2p_config.compliance.component_definition = 'plugins_public/tests/data/ocm/component-definition.json' +c2p_config.pvp_name = 'OCM' + +# Construct C2P +c2p = C2P(c2p_config) + +# Transform OSCAL (Compliance) to Policy +policy_template_dir = f'{TEST_DATA_DIR}/policy-resources' +config = PluginConfigOCM( + policy_template_dir=policy_template_dir, + deliverable_policy_dir=tmpdirname, + namespace='c2p', + paremeters_configmap_name='c2p-parameters', + cluster_selectors={'environment': 'dev'}, + policy_set_name='c2p test', +) +PluginOCM(config).generate_pvp_policy(c2p.get_policy()) + + +def tree(path: pathlib.Path, texts: list[str] = [], depth=0) -> list[str]: + prefix = '' + if depth > 0: + for _ in range(depth - 1): + prefix = prefix + ' ' + prefix = prefix + '- ' + for item in path.iterdir(): + texts.append(f'{prefix}{item.name}') + if item.is_dir(): + tree(item, texts, depth=depth + 1) + return texts + + +print('') +print(f'tree {tmpdirname}') +for text in tree(pathlib.Path(tmpdirname)): + print(text) diff --git a/samples_public/ocm/result_to_compliance.py b/samples_public/ocm/result_to_compliance.py new file mode 100644 index 0000000..8b83e27 --- /dev/null +++ b/samples_public/ocm/result_to_compliance.py @@ -0,0 +1,45 @@ +import argparse +import os +import pathlib +import sys + +import yaml + +from c2p.framework.c2p import C2P +from c2p.framework.models.c2p_config import C2PConfig, ComplianceOscal +from c2p.framework.models.raw_result import RawResult + +sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) +from plugins_public.plugins.ocm import PluginOCM + +TEST_DATA_DIR = 'plugins_public/tests/data/ocm' + +parser = argparse.ArgumentParser() +parser.add_argument( + '-p', + '--policy-result', + type=str, + default=f'{TEST_DATA_DIR}/policies.policy.open-cluster-management.io.yaml', + help='Path to a yaml file in which policies.policy.open-cluster-management.io resources are dumped.', + required=False, +) +args = parser.parse_args() + +# Setup c2p_config +c2p_config = C2PConfig() +c2p_config.compliance = ComplianceOscal() +c2p_config.compliance.component_definition = 'plugins_public/tests/data/ocm/component-definition.json' +c2p_config.pvp_name = 'OCM' +c2p_config.result_title = 'OCM Assessment Results' +c2p_config.result_description = 'OSCAL Assessment Results from OCM' + +# Create pvp_result from raw result via plugin +policies = yaml.safe_load(pathlib.Path(args.policy_result).open('r')) +pvp_raw_result = RawResult(data=policies['items']) +c2p_config.pvp_result = PluginOCM().generate_pvp_result(pvp_raw_result) + +# Transform pvp_result to OSCAL Assessment Result +c2p = C2P(c2p_config) +oscal_assessment_results = c2p.result_to_oscal() + +print(oscal_assessment_results.oscal_serialize_json(pretty=True)) diff --git a/scripts/shell/license.sh b/scripts/shell/license.sh new file mode 100755 index 0000000..7f16ff9 --- /dev/null +++ b/scripts/shell/license.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +license_file=./scripts/shell/license.txt + +directory=$1 + +function add_license() { + find $directory -name '*.py' | while read name + do + cat $license_file > /tmp/newfile + cat $name >> /tmp/newfile + cp /tmp/newfile $name + done +} + +add_license $directory \ No newline at end of file diff --git a/scripts/shell/license.txt b/scripts/shell/license.txt new file mode 100644 index 0000000..0e18e08 --- /dev/null +++ b/scripts/shell/license.txt @@ -0,0 +1,16 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..bd26775 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,15 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/c2p/__init__.py b/tests/c2p/__init__.py new file mode 100644 index 0000000..9d5e84d --- /dev/null +++ b/tests/c2p/__init__.py @@ -0,0 +1,32 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import pathlib +from distutils.util import strtobool + +from c2p.common import logging + +logger = logging.getLogger(__name__) + + +def write_test_result_to_file(output_path: pathlib.Path, data: str): + enabled = os.getenv('ENABLE_WRITE_TEST_RESULT_TO_FILE', 'false') + if strtobool(enabled): + try: + output_path.write_text(data) + except Exception as e: + logger.error(f'Failed to write test results to {output_path.as_posix()}\n {str(e)}') diff --git a/tests/c2p/framework/__init__.py b/tests/c2p/framework/__init__.py new file mode 100644 index 0000000..bd26775 --- /dev/null +++ b/tests/c2p/framework/__init__.py @@ -0,0 +1,15 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/c2p/framework/test_c2p.py b/tests/c2p/framework/test_c2p.py new file mode 100644 index 0000000..9766ded --- /dev/null +++ b/tests/c2p/framework/test_c2p.py @@ -0,0 +1,94 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import pathlib +from typing import Any, Dict, Tuple + +from pydantic import BaseModel +from trestle.oscal.assessment_results import AssessmentResults + +from c2p.framework.c2p import C2P +from c2p.framework.models.c2p_config import C2PConfig, ComplianceOscal +from c2p.framework.models.pvp_result import PVPResult +from tests.c2p import write_test_result_to_file + +COMPONENT_DEFINITION_TEST_DATA = pathlib.Path('tests/data/framework/c2p/component-definition.json') +PVP_RESULT_TEST_DATA = pathlib.Path('tests/data/framework/c2p/pvp-result.json') +EXPECTED_ASSESSMENT_RESULTS_DATA = pathlib.Path('tests/data/framework/c2p/assessment-results.json') +OUTPUT_PATH = EXPECTED_ASSESSMENT_RESULTS_DATA + + +def extract_dicts(d: Dict[str, Any], excludes=[]) -> Tuple[Dict[str, Any], Dict[str, Any]]: + primitives = [] + nested = [] + for key, value in d.items(): + if key in excludes: + continue + if isinstance(value, list) or isinstance(value, dict): + nested.append((key, value)) + else: + primitives.append((key, value)) + + return dict(primitives), dict(nested) + + +def assert_pydantic_object(actual: BaseModel, expect: BaseModel, exludes=[]): + actual, _ = extract_dicts(actual.dict(), excludes=exludes) + expect, _ = extract_dicts(expect.dict(), excludes=exludes) + assert actual == expect + + +def test_result_to_oscal(): + c2p_config = C2PConfig() + c2p_config.compliance = ComplianceOscal() + c2p_config.compliance.component_definition = COMPONENT_DEFINITION_TEST_DATA.as_posix() + c2p_config.pvp_name = 'OCM' + c2p_config.result_title = 'TEST Assessment Results' + c2p_config.result_description = 'OSCAL Assessment Results from TEST' + + pvp_result = json.load(PVP_RESULT_TEST_DATA.open('r')) + c2p_config.pvp_result = PVPResult.parse_obj(pvp_result) + + c2p = C2P(c2p_config) + assessment_results = c2p.result_to_oscal() + expect = AssessmentResults.parse_file(EXPECTED_ASSESSMENT_RESULTS_DATA) + + assert_pydantic_object(assessment_results.metadata, expect.metadata, exludes=['last_modified']) + assert_pydantic_object(assessment_results.import_ap, expect.import_ap) + actual_result = assessment_results.results[0] + expect_result = expect.results[0] + assert_pydantic_object(actual_result, expect_result, exludes=['uuid', 'start']) + actual_reviewed_controls = actual_result.reviewed_controls + expect_reviewed_controls = expect_result.reviewed_controls + assert expect_reviewed_controls == actual_reviewed_controls + + actual_observations = actual_result.observations + expect_observations = expect_result.observations + + assert len(actual_observations) == len(expect_observations) + for expect_o in expect_observations: + actual_o = next(filter(lambda x: x.title == expect_o.title, actual_observations), None) + assert actual_o != None + assert expect_o.props == actual_o.props + for expect_s in expect_o.subjects: + actual_s = next(filter(lambda x: x.title == expect_s.title, actual_o.subjects), None) + assert actual_s != None + assert expect_s.type == actual_s.type + assert list(filter(lambda x: x.name != 'evaluated-on', expect_s.props)) == list( + filter(lambda x: x.name != 'evaluated-on', actual_s.props) + ) + write_test_result_to_file(OUTPUT_PATH, assessment_results.json(exclude_none=True, indent=2)) diff --git a/tests/c2p/test_cli.py b/tests/c2p/test_cli.py new file mode 100644 index 0000000..950b311 --- /dev/null +++ b/tests/c2p/test_cli.py @@ -0,0 +1,47 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright 2024 IBM Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests for cli module.""" + +import sys + +import pytest +from _pytest.monkeypatch import MonkeyPatch + +from c2p import cli +from c2p.common import logging + +logger = logging.getLogger(__name__) + + +def test_run(monkeypatch: MonkeyPatch) -> None: + """Test cli call.""" + testargs = ['c2p'] + monkeypatch.setattr(sys, 'argv', testargs) + with pytest.raises(SystemExit) as pytest_wrapped_e: + cli.run() + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code > 0 + + +def test_version(monkeypatch: MonkeyPatch) -> None: + """Test cli call.""" + testargs = ['c2p', 'version'] + monkeypatch.setattr(sys, 'argv', testargs) + with pytest.raises(SystemExit) as pytest_wrapped_e: + cli.run() + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 0 diff --git a/tests/data/framework/c2p/assessment-results.json b/tests/data/framework/c2p/assessment-results.json new file mode 100644 index 0000000..bb6dac2 --- /dev/null +++ b/tests/data/framework/c2p/assessment-results.json @@ -0,0 +1,97 @@ +{ + "uuid": "490aa57a-b508-46f4-9552-1231d9468805", + "metadata": { + "title": "TEST Assessment Results", + "last_modified": "2024-03-22T08:28:11.000+00:00", + "version": "2.2.1", + "oscal_version": "1.0.4" + }, + "import_ap": { + "href": "https://not-available-for-now" + }, + "results": [ + { + "uuid": "2dc21238-a61e-48b4-9794-9d12f999c73c", + "title": "TEST Assessment Results", + "description": "OSCAL Assessment Results from TEST", + "start": "2024-03-22T08:28:11.000+00:00", + "reviewed_controls": { + "control_selections": [ + { + "include_controls": [ + { + "control_id": "cm-6", + "statement_ids": [] + } + ] + } + ] + }, + "observations": [ + { + "uuid": "c282e204-0f8f-4311-9c37-8dfe56464993", + "title": "policy-high-scan", + "description": "policy-high-scan", + "props": [ + { + "name": "assessment-rule-id", + "value": "test_configuration_check" + } + ], + "methods": [ + "AUTOMATED" + ], + "subjects": [ + { + "subject_uuid": "58ecbe30-9416-4804-a1aa-a3553fb21099", + "type": "cluster", + "title": "Cluster \"cluster1\"", + "props": [ + { + "name": "resource-id", + "value": "cluster1" + }, + { + "name": "result", + "value": "failure" + }, + { + "name": "evaluated-on", + "value": "2023-07-05T23:53:37+00:00" + }, + { + "name": "reason", + "value": "[c2p.policy-high-scan.176f1ddc441457e5] NonCompliant; violation - couldn't find mapping resource with kind ComplianceCheckResult, please check if you have CRD deployed" + } + ] + }, + { + "subject_uuid": "a4f602d7-acf1-428d-8f03-79855ea6aafb", + "type": "cluster", + "title": "Cluster \"cluster2\"", + "props": [ + { + "name": "resource-id", + "value": "cluster2" + }, + { + "name": "result", + "value": "failure" + }, + { + "name": "evaluated-on", + "value": "2023-07-05T23:51:56+00:00" + }, + { + "name": "reason", + "value": "[c2p.policy-high-scan.176f1dc4e29e1221] NonCompliant; violation - couldn't find mapping resource with kind ComplianceCheckResult, please check if you have CRD deployed" + } + ] + } + ], + "collected": "2024-03-22T08:17:46.000+00:00" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/data/framework/c2p/component-definition.json b/tests/data/framework/c2p/component-definition.json new file mode 100644 index 0000000..06179f3 --- /dev/null +++ b/tests/data/framework/c2p/component-definition.json @@ -0,0 +1,107 @@ +{ + "component-definition": { + "uuid": "fba79b7a-9a3d-4326-a657-71562985dbfc", + "metadata": { + "title": "Unit test based on OCM", + "last-modified": "2024-03-22T08:00:02+00:00", + "version": "1.0", + "oscal-version": "1.0.4" + }, + "components": [ + { + "uuid": "d69bf3b4-8eba-4543-8489-55dc8ed86e64", + "type": "Service", + "title": "Managed Kubernetes", + "description": "Managed Kubernetes cluster", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "test_configuration_check", + "remarks": "rule_set_0" + }, + { + "name": "Rule_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure deployment configuration is securely set up", + "remarks": "rule_set_0" + }, + { + "name": "Check_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-high-scan", + "remarks": "rule_set_0" + } + ], + "control-implementations": [ + { + "uuid": "57135f73-8f2b-43ea-9f9c-8ef3b3a62400", + "source": "https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json", + "description": "NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE", + "implemented-requirements": [ + { + "uuid": "c8eb7deb-f73d-44d6-96cc-e4e1497b10b7", + "control-id": "cm-6", + "description": "", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "test_configuration_check" + } + ] + } + ] + } + ] + }, + { + "uuid": "7e0e2270-0978-48d7-a413-691b3699c6dc", + "type": "Validation", + "title": "OCM", + "description": "OCM", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "test_configuration_check", + "remarks": "rule_set_1" + }, + { + "name": "Rule_Description", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "Ensure deployment configuration is securely set up", + "remarks": "rule_set_1" + }, + { + "name": "Check_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "policy-high-scan", + "remarks": "rule_set_1" + } + ], + "control-implementations": [ + { + "uuid": "20837a2b-db9f-4222-8cdc-55a4573be1c7", + "source": "https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_HIGH-baseline_profile.json", + "description": "NIST Special Publication 800-53 Revision 5 HIGH IMPACT BASELINE", + "implemented-requirements": [ + { + "uuid": "ca0eb376-9ca9-4d20-988b-45f94c42aefd", + "control-id": "na", + "description": "", + "props": [ + { + "name": "Rule_Id", + "ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/ibmcloud", + "value": "test_configuration_check" + } + ] + } + ] + } + ] + } + ] + } +} \ No newline at end of file diff --git a/tests/data/framework/c2p/pvp-result.json b/tests/data/framework/c2p/pvp-result.json new file mode 100644 index 0000000..684ef60 --- /dev/null +++ b/tests/data/framework/c2p/pvp-result.json @@ -0,0 +1,79 @@ +{ + "observations_by_check": [ + { + "check_id": "policy-deployment", + "methods": [ + "AUTOMATED" + ], + "subjects": [ + { + "title": "Cluster \"cluster1\"", + "type": "cluster", + "resource_id": "cluster1", + "result": "failure", + "evaluated_on": "2023-07-05T23:53:37.000+00:00", + "reason": "[c2p.policy-deployment.176f1ddc5591cb1c] NonCompliant; violation - deployments not found: [nginx-deployment] in namespace cluster1 missing; [nginx-deployment] in namespace kube-node-lease missing; [nginx-deployment] in namespace kube-public missing; [nginx-deployment] in namespace local-path-storage missing" + }, + { + "title": "Cluster \"cluster2\"", + "type": "cluster", + "resource_id": "cluster2", + "result": "failure", + "evaluated_on": "2023-07-05T23:51:56.000+00:00", + "reason": "[c2p.policy-deployment.176f1dc4e7de17cb] NonCompliant; violation - deployments not found: [nginx-deployment] in namespace cluster2 missing; [nginx-deployment] in namespace default missing; [nginx-deployment] in namespace kube-node-lease missing; [nginx-deployment] in namespace kube-public missing; [nginx-deployment] in namespace local-path-storage missing" + } + ], + "collected": "2024-03-22T08:17:46.000+00:00" + }, + { + "check_id": "policy-disallowed-roles", + "methods": [ + "AUTOMATED" + ], + "subjects": [ + { + "title": "Cluster \"cluster1\"", + "type": "cluster", + "resource_id": "cluster1", + "result": "pass", + "evaluated_on": "2023-07-05T23:52:34.000+00:00", + "reason": "[c2p.policy-disallowed-roles.176f1dcdc4c8d17e] Compliant; notification - roles in namespace cluster1; in namespace default; in namespace kube-node-lease; in namespace kube-public; in namespace local-path-storage missing as expected, therefore this Object template is compliant" + }, + { + "title": "Cluster \"cluster2\"", + "type": "cluster", + "resource_id": "cluster2", + "result": "pass", + "evaluated_on": "2023-07-05T23:51:50.000+00:00", + "reason": "[c2p.policy-disallowed-roles.176f1dc36e36b7b2] Compliant; notification - roles in namespace cluster2; in namespace default; in namespace kube-node-lease; in namespace kube-public; in namespace local-path-storage missing as expected, therefore this Object template is compliant" + } + ], + "collected": "2024-03-22T08:17:46.000+00:00" + }, + { + "check_id": "policy-high-scan", + "methods": [ + "AUTOMATED" + ], + "subjects": [ + { + "title": "Cluster \"cluster1\"", + "type": "cluster", + "resource_id": "cluster1", + "result": "failure", + "evaluated_on": "2023-07-05T23:53:37.000+00:00", + "reason": "[c2p.policy-high-scan.176f1ddc441457e5] NonCompliant; violation - couldn't find mapping resource with kind ComplianceCheckResult, please check if you have CRD deployed" + }, + { + "title": "Cluster \"cluster2\"", + "type": "cluster", + "resource_id": "cluster2", + "result": "failure", + "evaluated_on": "2023-07-05T23:51:56.000+00:00", + "reason": "[c2p.policy-high-scan.176f1dc4e29e1221] NonCompliant; violation - couldn't find mapping resource with kind ComplianceCheckResult, please check if you have CRD deployed" + } + ], + "collected": "2024-03-22T08:17:46.000+00:00" + } + ] +} \ No newline at end of file