Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shell quote support for Jinja macros #10524

Merged
merged 4 commits into from
May 4, 2023
Merged

Conversation

maage
Copy link
Contributor

@maage maage commented May 2, 2023

Description:

Quote a string to safely use as in a POSIX shell.

Handling quoting shell is quite hard when there is complex macro
workflow. This filter allows to quote where ever variable is used.

Name mirrors respective feature in ansible.

I also sorted jinja filters alphabetically for them to be neat.

Rationale:

When ever I look at bash remediations, there is multiple ways things can go sideways if variables contain shell metacharacters. There is sometimes extra checks.

If this feature is used, it provides clear security benefit.

Review Hints:

For now there is no test suite or any template that uses this.

maage added 2 commits May 2, 2023 18:38
Quote a string to safely use as in a POSIX shell.

Handling quoting shell is quite hard when there is complex macro
workflow. This filter allows to quote where ever variable is used.

Name mirrors respective feature in ansible.

usage:

foo={{{ FOO | quote }}}

If FOO requires additional quotes they are added, if not, they are not.
Result can be like:

foo=bar
or
foo='"bar"'

Implemented using python shlex quote
https://docs.python.org/3/library/shlex.html#shlex.quote
@openshift-ci
Copy link

openshift-ci bot commented May 2, 2023

Hi @maage. Thanks for your PR.

I'm waiting for a ComplianceAsCode member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@openshift-ci openshift-ci bot added the needs-ok-to-test Used by openshift-ci bot. label May 2, 2023
@github-actions
Copy link

github-actions bot commented May 2, 2023

Start a new ephemeral environment with changes proposed in this pull request:

Fedora Environment
Open in Gitpod

Oracle Linux 8 Environment
Open in Gitpod

@Mab879
Copy link
Member

Mab879 commented May 2, 2023

/ok-to-test

@openshift-ci openshift-ci bot added ok-to-test Used by openshift-ci bot. and removed needs-ok-to-test Used by openshift-ci bot. labels May 2, 2023
@Mab879 Mab879 added this to the 0.1.68 milestone May 2, 2023
@Mab879 Mab879 added the Infrastructure Our content build system label May 2, 2023
@Mab879 Mab879 self-assigned this May 3, 2023
@Mab879
Copy link
Member

Mab879 commented May 3, 2023

Do you have an example where this could be used?

@maage
Copy link
Contributor Author

maage commented May 3, 2023

It should be used anywhere where there is shellscript and it is not absolutely sure jinja value does not have shell metacharacters.

From 10-bash.jinja bash_ensure_pam_module_options start, set used jinja variables as shell variables using quote and then use them as normal shell variables.

pamFile={{{ pamFile | quote }}}
if [ -e "${pamFile}" ] ; then

This pattern would clearly split parts of shell scripts where there is first part to make all jinja parameters as shell parameters and then rest of the script is just pure shellscript. For somewhat complex parts that is not so. But simple macros like bash_ensure_pam_module_options this kind of conversion would provide clarity. When coding you should need to think only one domain and only one set of quotation rules.

And essentially any string that is not meant to be regexp but used in regexp context in shell script should be handled like:

type_rx={{{ type | escape_regex | quote }}}
module_rx={{{ module | escape_regex | quote }}}
    if grep -q -P "^\\s*(?"'!'"${type_rx}\\s)[[:alnum:]]+\\s+[[:alnum:]]+\\s+${module_rx}" < "${pamFile}" ; then

But that would require also standardizing s delim character in sed parts etc and then ensuring it is also quoted in escape_regex.

Also I think shell scripts should use

set -u

to catch any typos in variable names.

Another example from: shared/templates/pam_options/ansible.template

- name: Check the presence of "{{{ arg['argument'] }}}" argument in "{{{ MODULE }}}" module
  shell: |
    set -o pipefail
    grep -E '^\s*'{{{ TYPE | quote }}}'\s+'{{{ CONTROL_FLAG | quote }}}'\s+'{{{ MODULE quote }}}'.*\s+'{{{ arg['argument'] | quote }}}'(=|\s|\s*$)' {{{ PATH | quote }}} || true
  register: check_pam_module_argument_result

But anyways, above should be rewritten using command + argv, example below.

Also what is lacking is same stuff with ansible shell: tasks (with {{ }}).

Like: shared/templates/rsyslog_logfiles_attributes_modify/ansible.template

- name: '{{{ rule_title }}} - Extract log files old format'
  ansible.builtin.shell: |
    set -o pipefail
    grep -oP '^[^(\s|#|\$)]+[\s]+.*[\s]+-?(/+[^:;\s]+);*\.*$' {{ item.1.path | quote }} | \
    awk '{print $NF}' | \
    sed -e 's/^-//' || true
  loop: "{{ rsyslog_config_files.results | subelements('files') }}"
  register: log_files_old
  changed_when: False

Though above should be rewritten as awk / sed and use command, then there is no need to have quote.

Just like this should be like:

- name: '{{{ rule_title }}} - Get include files directives'
  ansible.builtin.command:
    argv:
      - awk
      - >-
        /)/{f=0} /include\(/{f=1} f{nf=gensub("^(include\\(|\\s*)file=\"(\\S+)\".*","\\2",1); if($0!=nf){print nf}}
      - rsyslog_etc_config
  register: rsyslog_new_inc
  changed_when: False
  failed_when: False

In most cases ansible shell: tasks should be converted to one command task and then pure ansible to parse the output.

@maage
Copy link
Contributor Author

maage commented May 3, 2023

Added documentation fragments for this and other filters. These could be improved though. I hope this was okay.

@codeclimate
Copy link

codeclimate bot commented May 3, 2023

Code Climate has analyzed commit 2a9ae08 and detected 0 issues on this pull request.

The test coverage on the diff in this pull request is 71.4% (50% is the threshold).

This pull request will bring the total coverage in the repository to 52.4% (0.0% change).

View more on Code Climate.

Copy link
Member

@Mab879 Mab879 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

@Mab879 Mab879 merged commit 25b4207 into ComplianceAsCode:master May 4, 2023
@maage maage deleted the quote-1 branch May 5, 2023 12:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Infrastructure Our content build system ok-to-test Used by openshift-ci bot.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants