Skip to content

Commit 18daeb6

Browse files
committed
Add support for object-templates-raw
Adds support for manifest files with only object-templates-raw field, which gets put into a ConfigurationPolicy. Signed-off-by: Jeffrey Luo <[email protected]>
1 parent 1a25c98 commit 18daeb6

File tree

4 files changed

+189
-6
lines changed

4 files changed

+189
-6
lines changed

internal/plugin_config_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,29 @@ spec:
8383
}
8484
}
8585

86+
func createObjectTemplatesRawManifest(t *testing.T, tmpDir, filename string) {
87+
t.Helper()
88+
89+
manifestsPath := path.Join(tmpDir, filename)
90+
yamlContent := `
91+
object-templates-raw: |
92+
- complianceType: musthave
93+
objectDefinition:
94+
apiVersion: v1
95+
kind: ConfigMap
96+
metadata:
97+
name: example
98+
namespace: default
99+
data:
100+
extraData: data
101+
`
102+
103+
err := os.WriteFile(manifestsPath, []byte(yamlContent), 0o666)
104+
if err != nil {
105+
t.Fatalf("Failed to write %s", manifestsPath)
106+
}
107+
}
108+
86109
func TestConfig(t *testing.T) {
87110
t.Parallel()
88111
tmpDir := t.TempDir()

internal/plugin_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,73 @@ spec:
13641364
assertEqual(t, output, expected)
13651365
}
13661366

1367+
func TestCreatePolicyFromObjectTemplatesRawManifest(t *testing.T) {
1368+
t.Parallel()
1369+
tmpDir := t.TempDir()
1370+
createObjectTemplatesRawManifest(t, tmpDir, "objectTemplatesRawPluginTest.yaml")
1371+
1372+
p := Plugin{}
1373+
p.PolicyDefaults.Namespace = "my-policies"
1374+
policyConf := types.PolicyConfig{
1375+
PolicyOptions: types.PolicyOptions{
1376+
Categories: []string{"AC Access Control"},
1377+
Controls: []string{"AC-3 Access Enforcement"},
1378+
Standards: []string{"NIST SP 800-53"},
1379+
},
1380+
Name: "policy-app-config",
1381+
Manifests: []types.Manifest{
1382+
{Path: path.Join(tmpDir, "objectTemplatesRawPluginTest.yaml")},
1383+
},
1384+
}
1385+
p.Policies = append(p.Policies, policyConf)
1386+
p.applyDefaults(map[string]interface{}{})
1387+
1388+
err := p.createPolicy(&p.Policies[0])
1389+
if err != nil {
1390+
t.Fatal(err.Error())
1391+
}
1392+
1393+
output := p.outputBuffer.String()
1394+
1395+
expected := `
1396+
---
1397+
apiVersion: policy.open-cluster-management.io/v1
1398+
kind: Policy
1399+
metadata:
1400+
annotations:
1401+
policy.open-cluster-management.io/categories: AC Access Control
1402+
policy.open-cluster-management.io/controls: AC-3 Access Enforcement
1403+
policy.open-cluster-management.io/description: ""
1404+
policy.open-cluster-management.io/standards: NIST SP 800-53
1405+
name: policy-app-config
1406+
namespace: my-policies
1407+
spec:
1408+
disabled: false
1409+
policy-templates:
1410+
- objectDefinition:
1411+
apiVersion: policy.open-cluster-management.io/v1
1412+
kind: ConfigurationPolicy
1413+
metadata:
1414+
name: policy-app-config
1415+
spec:
1416+
object-templates-raw: |
1417+
- complianceType: musthave
1418+
objectDefinition:
1419+
apiVersion: v1
1420+
kind: ConfigMap
1421+
metadata:
1422+
name: example
1423+
namespace: default
1424+
data:
1425+
extraData: data
1426+
remediationAction: inform
1427+
severity: low
1428+
remediationAction: inform
1429+
`
1430+
expected = strings.TrimPrefix(expected, "\n")
1431+
assertEqual(t, output, expected)
1432+
}
1433+
13671434
func TestCreatePolicyWithGkConstraintTemplate(t *testing.T) {
13681435
t.Parallel()
13691436
tmpDir := t.TempDir()

internal/utils.go

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,16 @@ func getPolicyTemplates(policyConf *types.PolicyConfig) ([]map[string]interface{
189189
if isPolicyTypeManifest {
190190
policyTemplate := map[string]interface{}{"objectDefinition": manifest}
191191

192+
_, found, _ := unstructured.NestedString(manifest, "object-templates-raw")
193+
if found {
194+
policyTemplate = buildPolicyTemplate(
195+
policyConf,
196+
len(policyTemplates)+1,
197+
manifest["object-templates-raw"],
198+
&policyConf.Manifests[i].ConfigurationPolicyOptions,
199+
)
200+
}
201+
192202
// Only set dependency options if it's an OCM policy
193203
if isOcmPolicy {
194204
setTemplateOptions(policyTemplate, ignorePending, extraDeps)
@@ -309,6 +319,13 @@ func setTemplateOptions(tmpl map[string]interface{}, ignorePending bool, extraDe
309319
// - the manifest is a root policy manifest
310320
// - the manifest is invalid because it is missing a name
311321
func isPolicyTypeManifest(manifest map[string]interface{}, informGatekeeperPolicies bool) (bool, bool, error) {
322+
// check for object-templates-raw separate from policies since they have separate requirements
323+
_, found, _ := unstructured.NestedString(manifest, "object-templates-raw")
324+
if found {
325+
// return true for isPolicyType, since object-templates-raw is in a ConfigurationPolicy
326+
return true, false, nil
327+
}
328+
312329
apiVersion, found, err := unstructured.NestedString(manifest, "apiVersion")
313330
if !found || err != nil {
314331
return false, false, errors.New("invalid or not found apiVersion")
@@ -398,7 +415,7 @@ func processKustomizeDir(path string) ([]map[string]interface{}, error) {
398415
func buildPolicyTemplate(
399416
policyConf *types.PolicyConfig,
400417
policyNum int,
401-
objectTemplates []map[string]interface{},
418+
objectTemplates interface{},
402419
configPolicyOptionsOverrides *types.ConfigurationPolicyOptions,
403420
) map[string]interface{} {
404421
var name string
@@ -408,18 +425,26 @@ func buildPolicyTemplate(
408425
name = policyConf.Name
409426
}
410427

428+
policySpec := map[string]interface{}{
429+
"remediationAction": policyConf.RemediationAction,
430+
"severity": policyConf.Severity,
431+
}
432+
433+
switch objectTemplates.(type) {
434+
case string:
435+
policySpec["object-templates-raw"] = objectTemplates
436+
case []map[string]interface{}:
437+
policySpec["object-templates"] = objectTemplates
438+
}
439+
411440
policyTemplate := map[string]interface{}{
412441
"objectDefinition": map[string]interface{}{
413442
"apiVersion": policyAPIVersion,
414443
"kind": configPolicyKind,
415444
"metadata": map[string]interface{}{
416445
"name": name,
417446
},
418-
"spec": map[string]interface{}{
419-
"object-templates": objectTemplates,
420-
"remediationAction": policyConf.RemediationAction,
421-
"severity": policyConf.Severity,
422-
},
447+
"spec": policySpec,
423448
},
424449
}
425450

internal/utils_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,74 @@ func TestGetPolicyTemplateInvalidManifest(t *testing.T) {
12621262
assertEqual(t, err.Error(), expected)
12631263
}
12641264

1265+
func TestGetPolicyTemplateObjectTemplatesRaw(t *testing.T) {
1266+
t.Parallel()
1267+
tmpDir := t.TempDir()
1268+
manifestPath := path.Join(tmpDir, "configmap.yaml")
1269+
manifestYAML := `
1270+
object-templates-raw: |
1271+
- complianceType: musthave
1272+
objectDefinition:
1273+
apiVersion: v1
1274+
kind: ConfigMap
1275+
metadata:
1276+
name: example
1277+
namespace: default
1278+
data:
1279+
extraData: data
1280+
`
1281+
manifestYAMLContent := `- complianceType: musthave
1282+
objectDefinition:
1283+
apiVersion: v1
1284+
kind: ConfigMap
1285+
metadata:
1286+
name: example
1287+
namespace: default
1288+
data:
1289+
extraData: data
1290+
`
1291+
1292+
err := os.WriteFile(manifestPath, []byte(manifestYAML), 0o666)
1293+
if err != nil {
1294+
t.Fatalf("Failed to write %s", manifestPath)
1295+
}
1296+
1297+
policyConf := types.PolicyConfig{
1298+
PolicyOptions: types.PolicyOptions{
1299+
ConsolidateManifests: true,
1300+
},
1301+
ConfigurationPolicyOptions: types.ConfigurationPolicyOptions{
1302+
ComplianceType: "musthave",
1303+
RemediationAction: "enforce",
1304+
Severity: "low",
1305+
},
1306+
Manifests: []types.Manifest{{Path: manifestPath}},
1307+
Name: "configpolicy-object-templates-raw-config",
1308+
}
1309+
1310+
policyTemplates, err := getPolicyTemplates(&policyConf)
1311+
if err != nil {
1312+
t.Fatalf("Failed to get the policy templates: %v", err)
1313+
}
1314+
1315+
assertEqual(t, len(policyTemplates), 1)
1316+
1317+
policyTemplate := policyTemplates[0]
1318+
objdef := policyTemplate["objectDefinition"].(map[string]interface{})
1319+
1320+
spec, ok := objdef["spec"].(map[string]interface{})
1321+
if !ok {
1322+
t.Fatal("The spec field is an invalid format")
1323+
}
1324+
1325+
objectTemplatesRaw, ok := spec["object-templates-raw"].(string)
1326+
if !ok {
1327+
t.Fatal("The object-templates-raw field is an invalid format")
1328+
}
1329+
1330+
assertEqual(t, len(objectTemplatesRaw), len(manifestYAMLContent))
1331+
}
1332+
12651333
func TestUnmarshalManifestFile(t *testing.T) {
12661334
t.Parallel()
12671335
tmpDir := t.TempDir()

0 commit comments

Comments
 (0)