Skip to content

Commit

Permalink
Ansible: mark variables from custom resources as unsafe
Browse files Browse the repository at this point in the history
User provided values from the custom resource are tagged
unsafe by default.
  • Loading branch information
varshaprasad96 committed Feb 22, 2021
1 parent 34a55dd commit 07b20b7
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 1 deletion.
5 changes: 5 additions & 0 deletions changelog/fragments/mark-variables-unsafe.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
entries:
- description: >
Mark the input variables from custom resources as unsafe by default in Ansible operators.
kind: bugfix
breaking: false
30 changes: 29 additions & 1 deletion internal/ansible/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ func (r *runner) makeParameters(u *unstructured.Unstructured) map[string]interfa
parameters = paramconv.MapToSnake(spec)
} else {
for k, v := range spec {
parameters[k] = v
parameters[k] = markUnsafe(v)
}
}

Expand All @@ -360,6 +360,34 @@ func (r *runner) makeParameters(u *unstructured.Unstructured) map[string]interfa
return parameters
}

// markUnsafe recursively checks for string values and marks them unsafe.
// for eg:
// spec:
// key: "val"
// would be marked unsafe in JSON format as:
// spec:
// key: map{__ansible_unsafe:"val"}
func markUnsafe(values interface{}) interface{} {
switch v := values.(type) {
case []interface{}:
var p []interface{}
for _, n := range v {
p = append(p, markUnsafe(n))
}
return p
case map[string]interface{}:
m := make(map[string]interface{})
for k, v := range v {
m[k] = markUnsafe(v)
}
return m
case string:
return map[string]interface{}{"__ansible_unsafe": values}
default:
return values
}
}

// escapeAnsibleKey - replaces characters that would result in an inaccessible Ansible parameter with underscores
// ie, _cert-manager.k8s.io would be converted to _cert_manager_k8s_io
func escapeAnsibleKey(key string) string {
Expand Down
125 changes: 125 additions & 0 deletions internal/ansible/runner/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,128 @@ func TestAnsibleVerbosityString(t *testing.T) {
}
}
}

func TestMakeParameters(t *testing.T) {
var (
inputSpec string = "testKey"
)

testCases := []struct {
name string
inputParams unstructured.Unstructured
expectedSafeParams interface{}
}{
{
name: "should mark values passed as string unsafe",
inputParams: unstructured.Unstructured{
Object: map[string]interface{}{
"spec": map[string]interface{}{
inputSpec: "testVal",
},
},
},
expectedSafeParams: map[string]interface{}{
"__ansible_unsafe": "testVal",
},
},
{
name: "should not mark integers unsafe",
inputParams: unstructured.Unstructured{
Object: map[string]interface{}{
"spec": map[string]interface{}{
inputSpec: 3,
},
},
},
expectedSafeParams: 3,
},
{
name: "should recursively mark values in dictionary as unsafe",
inputParams: unstructured.Unstructured{
Object: map[string]interface{}{
"spec": map[string]interface{}{
inputSpec: map[string]interface{}{
"testsubKey1": "val1",
"testsubKey2": "val2",
},
},
},
},
expectedSafeParams: map[string]interface{}{
"testsubKey1": map[string]interface{}{
"__ansible_unsafe": "val1",
},
"testsubKey2": map[string]interface{}{
"__ansible_unsafe": "val2",
},
},
},
{
name: "should recursively mark values in list as unsafe",
inputParams: unstructured.Unstructured{
Object: map[string]interface{}{
"spec": map[string]interface{}{
inputSpec: []interface{}{
"testVal1",
"testVal2",
},
},
},
},
expectedSafeParams: []interface{}{
map[string]interface{}{
"__ansible_unsafe": "testVal1",
},
map[string]interface{}{
"__ansible_unsafe": "testVal2",
},
},
},
{
name: "should recursively mark values in list/dict as unsafe",
inputParams: unstructured.Unstructured{
Object: map[string]interface{}{
"spec": map[string]interface{}{
inputSpec: []interface{}{
"testVal1",
"testVal2",
map[string]interface{}{
"testVal3": 3,
"testVal4": "__^&{__)",
},
},
},
},
},
expectedSafeParams: []interface{}{
map[string]interface{}{
"__ansible_unsafe": "testVal1",
},
map[string]interface{}{
"__ansible_unsafe": "testVal2",
},
map[string]interface{}{
"testVal3": 3,
"testVal4": map[string]interface{}{
"__ansible_unsafe": "__^&{__)",
},
},
},
},
}

for _, tc := range testCases {
testRunner := runner{}
parameters := testRunner.makeParameters(&tc.inputParams)

val, ok := parameters[inputSpec]
if !ok {
t.Fatalf("Error occurred, value %s in spec is missing", inputSpec)
} else {
eq := reflect.DeepEqual(val, tc.expectedSafeParams)
if !eq {
t.Errorf("Error occurred, parameters %v are not marked unsafe", val)
}
}
}
}

0 comments on commit 07b20b7

Please sign in to comment.