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.

Signed-off-by: varshaprasad96 <varshaprasad96@gmail.com>
  • Loading branch information
varshaprasad96 committed Feb 22, 2021
1 parent 34a55dd commit c611724
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 c611724

Please sign in to comment.