From 5ce80c355d78467a7d1e1126bdd996e1160e5814 Mon Sep 17 00:00:00 2001 From: nia-vf1 <92175447+nia-vf1@users.noreply.github.com> Date: Thu, 10 Oct 2024 19:11:49 +0100 Subject: [PATCH] POL-1365 Update Policy Permissions Automation - support for crossed-dagger symbol (#2678) * updated fail message for AWS, Azure, Google Cloud, and Flexera permissions that should have a footnote * updated condition to support dagger and cross-dagger symbol when looking for permission lines that end with a footnote symbol * updated condition to support dagger and crossed dagger symbol when checking the permission/s footnote/s themselves * remove references to asterix and replace with footnote_symbol to be more generic * updated ruby script for generating policy master permissions to support crossed dagger symbol * test footnote symbol * test footnote symbol 2 * test footnote symbol 3 * test footnote symbol 4 * test footnote symbol 5 * attempt again * attempt 2 with dagger symbol only * replace dagger symbol with unicode * update the perm testers to support the new symbols using unicode * attempt 2 with dagger symbol only, but now without the footnote * attempt 2 with cross-dagger symbol only, also change to unicode in dangerfile readme script * attempt 2 with both dagger and cross-dagger, however, dagger is missing footnote * update readme script to account for different scenarios of missing footnotes * change permission action logic * test both dagger and crossed dagger with footnotes (expecting all checks to pass) * change permission action logic for Azure * revert changes made to Schedule EC2 events policy readme * change permission action logic for Google Cloud * change permission action logic for Flexera provider * add code to support 3 additional symbols - section, double-vertical bar, pilcrow * change to Google policy readme to test dangerfile check * revert changes * add changes to Microsoft policy readme to test dangerfile check * footnote asterisk instead of section symbol * now testing double-veritcal bar and pilcrow symbols * minor change to language in error message with regards to missing footnotes * now testing error message to see if it includes one for a missing asterisk footnote * revert changes to policy template readme * add support for section, double-vertical bar and pilcrow symbols in the master permissions script * fixed if statement --- .dangerfile/readme_tests.rb | 162 +++++++++++++----- .../generate_policy_master_permissions.rb | 15 +- 2 files changed, 135 insertions(+), 42 deletions(-) diff --git a/.dangerfile/readme_tests.rb b/.dangerfile/readme_tests.rb index c6da4b47d7..a56d4eb293 100644 --- a/.dangerfile/readme_tests.rb +++ b/.dangerfile/readme_tests.rb @@ -264,8 +264,10 @@ def readme_invalid_credentials?(file, file_lines) fail_message += "```- [**AWS Credential**](https://docs.flexera.com/flexera/EN/Automation/ProviderCredentials.htm#automationadmin_1982464505_1121575) (*provider=aws*) which has the following permissions:```\n\n" end - aws_perm_tester = /`[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*:[a-zA-Z0-9]+`(?:\*)?$/ - asterix_found = 0 + aws_perm_tester = /`[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*:[a-zA-Z0-9]+`(?:[\*\u2020\u2021\u00a7\u2016\u00b6])?$/ + + # Hash to track the presence of each footnote symbol in the permission list + footnote_symbols = { "*" => false, "†" => false, "‡" => false, "§" => false, "‖" => false, "¶" => false } permission_list_found = 0 aws_permission_text.each_with_index do |line, index| @@ -277,31 +279,51 @@ def readme_invalid_credentials?(file, file_lines) if !line.start_with?(" - ") permission_list_found = 2 else - asterix_found = 1 if line.strip.end_with?("*") - - if !line.split(" - ")[1].match?(aws_perm_tester) + footnote_symbols["*"] = true if line.strip.end_with?("*") + footnote_symbols["†"] = true if line.strip.end_with?("\u2020") + footnote_symbols["‡"] = true if line.strip.end_with?("\u2021") + footnote_symbols["§"] = true if line.strip.end_with?("\u00a7") + footnote_symbols["‖"] = true if line.strip.end_with?("\u2016") + footnote_symbols["¶"] = true if line.strip.end_with?("\u00b6") + + permission_action = line.split(" - ")[1] + if permission_action.nil? || !permission_action.match?(aws_perm_tester) fail_message += "Line #{line_number.to_s}: AWS permission list item formatted incorrectly. Please make sure all list items are formatted like the following examples:\n\n" fail_message += "``` - `rds:DeleteDBSnapshot`*```\n" + fail_message += "``` - `ec2:TerminateInstances`†```\n" fail_message += "``` - `sts:GetCallerIdentity` ```\n" fail_message += "``` - `cloudtrail:LookupEvents` ```\n\n" end end end + end - asterix_found = 2 if asterix_found == 1 && line.start_with?(' \* ') + # Check for missing footnotes for any symbols that were found in the permissions list + footnote_symbols.each do |symbol, found| + next unless found # Only check if the symbol was found in the permission list + + # Search for corresponding footnote explanation + if symbol == "*" + if !aws_permission_text.any? { |line| line.strip.start_with?("\\*") } + fail_message += "Permission list contains a permission with an asterisk (*), but no corresponding footnote explaining it. Please add a footnote starting with ` \\* ` like so:\n\n" + fail_message += "``` \\* Only required for taking action; the policy will still function in a read-only capacity without these permissions.```\n" + end + else + if !aws_permission_text.any? { |line| line.strip.start_with?(symbol) } + fail_message += "Permission list contains a permission with a #{symbol} symbol, but no corresponding footnote explaining it. Please add a footnote starting with ` #{symbol} ` like so:\n\n" + fail_message += "``` #{symbol} Only required for taking action; the policy will still function in a read-only capacity without these permissions.```\n" + end + end end + # Check if no permission list was found if permission_list_found == 0 fail_message += "AWS permission list missing or formatted incorrectly. Please ensure there is a list of permissions beneath the AWS permission statement. Each list item should begin with [space][space][hyphen][space] like so:\n\n" fail_message += "``` - `rds:DeleteDBSnapshot`*```\n" + fail_message += "``` - `ec2:TerminateInstances`†```\n" fail_message += "``` - `sts:GetCallerIdentity` ```\n" fail_message += "``` - `cloudtrail:LookupEvents` ```\n\n" end - - if asterix_found == 1 - fail_message += "AWS permission list contains a permission with an asterix but no footnote explaning why or the footnote is formatted incorrectly. The footnote should indicate what is special about these permissions; in most cases, this will be an explanation that the permission is optional and only needed for policy actions. Please add a footnote that begins with [space][space][backslash][asterix][space] like so:\n\n" - fail_message += "``` \\* Only required for taking action; the policy will still function in a read-only capacity without these permissions.```\n\n" - end end if azure_permission_line @@ -310,8 +332,10 @@ def readme_invalid_credentials?(file, file_lines) fail_message += "```- [**Azure Resource Manager Credential**](https://docs.flexera.com/flexera/EN/Automation/ProviderCredentials.htm#automationadmin_109256743_1124668) (*provider=azure_rm*) which has the following permissions:```\n\n" end - azure_perm_tester = /^`Microsoft\.[a-zA-Z]+\/[a-zA-Z]+\/[a-zA-Z]+(?:\/[a-zA-Z]+)*`(?:\*)?$/ - asterix_found = 0 + azure_perm_tester = /^`Microsoft\.[a-zA-Z]+\/[a-zA-Z]+\/[a-zA-Z]+(?:\/[a-zA-Z]+)*`(?:[\*\u2020\u2021\u00a7\u2016\u00b6])?$/ + + # Hash to track the presence of each footnote symbol in the permission list + footnote_symbols = { "*" => false, "†" => false, "‡" => false, "§" => false, "‖" => false, "¶" => false } permission_list_found = 0 azure_permission_text.each_with_index do |line, index| @@ -323,9 +347,15 @@ def readme_invalid_credentials?(file, file_lines) if !line.start_with?(" - ") permission_list_found = 2 else - asterix_found = 1 if line.strip.end_with?("*") - - if !line.split(" - ")[1].match?(azure_perm_tester) + footnote_symbols["*"] = true if line.strip.end_with?("*") + footnote_symbols["†"] = true if line.strip.end_with?("\u2020") + footnote_symbols["‡"] = true if line.strip.end_with?("\u2021") + footnote_symbols["§"] = true if line.strip.end_with?("\u00a7") + footnote_symbols["‖"] = true if line.strip.end_with?("\u2016") + footnote_symbols["¶"] = true if line.strip.end_with?("\u00b6") + + permission_action = line.split(" - ")[1] + if permission_action.nil? || !permission_action.match?(azure_perm_tester) fail_message += "Line #{line_number.to_s}: Azure permission list item formatted incorrectly. Please make sure all list items are formatted like the following examples:\n\n" fail_message += "``` - `Microsoft.Compute/snapshots/delete`*```\n" fail_message += "``` - `Microsoft.Compute/snapshots/read` ```\n" @@ -333,21 +363,33 @@ def readme_invalid_credentials?(file, file_lines) end end end + end + + # Check for missing footnotes for any symbols that were found in the permissions list + footnote_symbols.each do |symbol, found| + next unless found # Only check if the symbol was found in the permission list - asterix_found = 2 if asterix_found == 1 && line.start_with?(' \* ') + # Search for corresponding footnote explanation + if symbol == "*" + if !azure_permission_text.any? { |line| line.strip.start_with?("\\*") } + fail_message += "Permission list contains a permission with an asterisk (*), but no corresponding footnote explaining it. Please add a footnote starting with ` \\* ` like so:\n\n" + fail_message += "``` \\* Only required for taking action; the policy will still function in a read-only capacity without these permissions.```\n" + end + else + if !azure_permission_text.any? { |line| line.strip.start_with?(symbol) } + fail_message += "Permission list contains a permission with a #{symbol} symbol, but no corresponding footnote explaining it. Please add a footnote starting with ` #{symbol} ` like so:\n\n" + fail_message += "``` #{symbol} Only required for taking action; the policy will still function in a read-only capacity without these permissions.```\n" + end + end end + # Check if no permission list was found if permission_list_found == 0 fail_message += "Azure permission list missing or formatted incorrectly. Please ensure there is a list of permissions beneath the Azure permission statement. Each list item should begin with [space][space][hyphen][space] like so:\n\n" fail_message += "``` - `Microsoft.Compute/snapshots/delete`*```\n" fail_message += "``` - `Microsoft.Compute/snapshots/read` ```\n" fail_message += "``` - `Microsoft.Insights/metrics/read` ```\n\n" end - - if asterix_found == 1 - fail_message += "Azure permission list contains a permission with an asterix but no footnote explaning why or the footnote is formatted incorrectly. The footnote should indicate what is special about these permissions; in most cases, this will be an explanation that the permission is optional and only needed for policy actions. Please add a footnote that begins with [space][space][backslash][asterix][space] like so:\n\n" - fail_message += "``` \\* Only required for taking action; the policy will still function in a read-only capacity without these permissions.```\n\n" - end end if google_permission_line @@ -356,8 +398,10 @@ def readme_invalid_credentials?(file, file_lines) fail_message += "```- [**Google Cloud Credential**](https://docs.flexera.com/flexera/EN/Automation/ProviderCredentials.htm#automationadmin_4083446696_1121577) (*provider=gce*) which has the following:```\n\n" end - google_perm_tester = /^`[a-zA-Z]+\.[a-zA-Z]+\.[a-zA-Z]+(?:\.[a-zA-Z]+)*`(?:\*)?$/ - asterix_found = 0 + google_perm_tester = /^`[a-zA-Z]+\.[a-zA-Z]+\.[a-zA-Z]+(?:\.[a-zA-Z]+)*`(?:[\*\u2020\u2021\u00a7\u2016\u00b6])?$/ + + # Hash to track the presence of each footnote symbol in the permission list + footnote_symbols = { "*" => false, "†" => false, "‡" => false, "§" => false, "‖" => false, "¶" => false } permission_list_found = 0 google_permission_text.each_with_index do |line, index| @@ -369,31 +413,50 @@ def readme_invalid_credentials?(file, file_lines) if !line.start_with?(" - ") permission_list_found = 2 else - asterix_found = 1 if line.strip.end_with?("*") + footnote_symbols["*"] = true if line.strip.end_with?("*") + footnote_symbols["†"] = true if line.strip.end_with?("\u2020") + footnote_symbols["‡"] = true if line.strip.end_with?("\u2021") + footnote_symbols["§"] = true if line.strip.end_with?("\u00a7") + footnote_symbols["‖"] = true if line.strip.end_with?("\u2016") + footnote_symbols["¶"] = true if line.strip.end_with?("\u00b6") if !line.split(" - ")[1].match?(google_perm_tester) fail_message += "Line #{line_number.to_s}: Google permission list item formatted incorrectly. Please make sure all list items are formatted like the following examples:\n\n" fail_message += "``` - `resourcemanager.projects.get`*```\n" + fail_message += "``` - `recommender.computeInstanceMachineTypeRecommendations.list`†```\n" fail_message += "``` - `compute.regions.list` ```\n" fail_message += "``` - `billing.resourceCosts.get` ```\n\n" end end end + end - asterix_found = 2 if asterix_found == 1 && line.start_with?(' \* ') + # Check for missing footnotes for any symbols that were found in the permissions list + footnote_symbols.each do |symbol, found| + next unless found # Only check if the symbol was found in the permission list + + # Search for corresponding footnote explanation + if symbol == "*" + if !google_permission_text.any? { |line| line.strip.start_with?("\\*") } + fail_message += "Permission list contains a permission with an asterisk (*), but no corresponding footnote explaining it. Please add a footnote starting with ` \\* ` like so:\n\n" + fail_message += "``` \\* Only required for taking action; the policy will still function in a read-only capacity without these permissions.```\n" + end + else + if !google_permission_text.any? { |line| line.strip.start_with?(symbol) } + fail_message += "Permission list contains a permission with a #{symbol} symbol, but no corresponding footnote explaining it. Please add a footnote starting with ` #{symbol} ` like so:\n\n" + fail_message += "``` #{symbol} Only required for taking action; the policy will still function in a read-only capacity without these permissions.```\n" + end + end end + # Check if no permission list was found if permission_list_found == 0 fail_message += "Google permission list missing or formatted incorrectly. Please ensure there is a list of permissions beneath the Google permission statement. Each list item should begin with [space][space][hyphen][space] like so:\n\n" fail_message += "``` - `resourcemanager.projects.get`*```\n" + fail_message += "``` - `recommender.computeInstanceMachineTypeRecommendations.list`†```\n" fail_message += "``` - `compute.regions.list` ```\n" fail_message += "``` - `billing.resourceCosts.get` ```\n\n" end - - if asterix_found == 1 - fail_message += "Google permission list contains a permission with an asterix but no footnote explaning why or the footnote is formatted incorrectly. The footnote should indicate what is special about these permissions; in most cases, this will be an explanation that the permission is optional and only needed for policy actions. Please add a footnote that begins with [space][space][backslash][asterix][space] like so:\n\n" - fail_message += "``` \\* Only required for taking action; the policy will still function in a read-only capacity without these permissions.```\n\n" - end end if flexera_permission_line @@ -402,8 +465,10 @@ def readme_invalid_credentials?(file, file_lines) fail_message += "```- [**Flexera Credential**](https://docs.flexera.com/flexera/EN/Automation/ProviderCredentials.htm) (*provider=flexera*) which has the following roles:```\n\n" end - flexera_perm_tester = /^`[a-zA-Z0-9\-_\.]+`(?:\*)?$/ - asterix_found = 0 + flexera_perm_tester = /^`[a-zA-Z0-9\-_\.]+`(?:[\*\u2020\u2021\u00a7\u2016\u00b6])?$/ + + # Hash to track the presence of each footnote symbol in the permission list + footnote_symbols = { "*" => false, "†" => false, "‡" => false, "§" => false, "‖" => false, "¶" => false } permission_list_found = 0 flexera_permission_text.each_with_index do |line, index| @@ -415,7 +480,12 @@ def readme_invalid_credentials?(file, file_lines) if !line.start_with?(" - ") permission_list_found = 2 else - asterix_found = 1 if line.strip.end_with?("*") + footnote_symbols["*"] = true if line.strip.end_with?("*") + footnote_symbols["†"] = true if line.strip.end_with?("\u2020") + footnote_symbols["‡"] = true if line.strip.end_with?("\u2021") + footnote_symbols["§"] = true if line.strip.end_with?("\u00a7") + footnote_symbols["‖"] = true if line.strip.end_with?("\u2016") + footnote_symbols["¶"] = true if line.strip.end_with?("\u00b6") if !line.split(" - ")[1].match?(flexera_perm_tester) fail_message += "Line #{line_number.to_s}: Flexera permission list item formatted incorrectly. Please make sure all list items are formatted like the following examples:\n\n" @@ -423,19 +493,31 @@ def readme_invalid_credentials?(file, file_lines) end end end + end - asterix_found = 2 if asterix_found == 1 && line.start_with?(' \* ') + # Check for missing footnotes for any symbols that were found in the permissions list + footnote_symbols.each do |symbol, found| + next unless found # Only check if the symbol was found in the permission list + + # Search for corresponding footnote explanation + if symbol == "*" + if !flexera_permission_text.any? { |line| line.strip.start_with?("\\*") } + fail_message += "Permission list contains a permission with an asterisk (*), but no corresponding footnote explaining it. Please add a footnote starting with ` \\* ` like so:\n\n" + fail_message += "``` \\* Only required for taking action; the policy will still function in a read-only capacity without these permissions.```\n" + end + else + if !flexera_permission_text.any? { |line| line.strip.start_with?(symbol) } + fail_message += "Permission list contains a permission with a #{symbol} symbol, but no corresponding footnote explaining it. Please add a footnote starting with ` #{symbol} ` like so:\n\n" + fail_message += "``` #{symbol} Only required for taking action; the policy will still function in a read-only capacity without these permissions.```\n" + end + end end + # Check if no permission list was found if permission_list_found == 0 fail_message += "Flexera permission list missing or formatted incorrectly. Please ensure there is a list of permissions beneath the Flexera permission statement. Each list item should begin with [space][space][hyphen][space] like so:\n\n" fail_message += "``` - `billing_center_viewer`*```\n\n" end - - if asterix_found == 1 - fail_message += "Flexera permission list contains a permission with an asterix but no footnote explaning why or the footnote is formatted incorrectly. The footnote should indicate what is special about these permissions; in most cases, this will be an explanation that the permission is optional and only needed for policy actions. Please add a footnote that begins with [space][space][backslash][asterix][space] like so:\n\n" - fail_message += "``` \\* Only required for taking action; the policy will still function in a read-only capacity without these permissions.```\n\n" - end end fail_message = "README.md has problems with how credential permissions are presented:\n\n" + fail_message if !fail_message.empty? diff --git a/tools/policy_master_permission_generation/generate_policy_master_permissions.rb b/tools/policy_master_permission_generation/generate_policy_master_permissions.rb index 188c32f30b..84a5d747d2 100644 --- a/tools/policy_master_permission_generation/generate_policy_master_permissions.rb +++ b/tools/policy_master_permission_generation/generate_policy_master_permissions.rb @@ -99,9 +99,8 @@ def extract_permissions_from_readme(readme_content) # Extract the text from this section section_text = readme_content[section_start..-1] - # Find the line starting with '/*' or '†' to get any specific notes around permissions from the README + # Find the line starting with '/*', '†', '‡', '§', '‖' or '¶' to get any specific notes around permissions from the README list_of_notes = [] - # note = "" section_text.each_line do |line| break if line.strip.start_with?( "##", "###", "- [**") && !line.strip.start_with?(section) @@ -111,6 +110,18 @@ def extract_permissions_from_readme(readme_content) elsif line.strip.start_with?("\u2020") dagger_note = line.strip.sub(/^\†\s*/, '') list_of_notes << { symbol: "†", detail: dagger_note } + elsif line.strip.start_with?("\u2021") + cross_dagger_note = line.strip.sub(/^\‡\s*/, '') + list_of_notes << { symbol: "‡", detail: cross_dagger_note } + elsif line.strip.start_with?("\u00a7") + section_note = line.strip.sub(/^\§\s*/, '') + list_of_notes << { symbol: "§", detail: section_note } + elsif line.strip.start_with?("\u2016") + vertical_bar_note = line.strip.sub(/^\‖\s*/, '') + list_of_notes << { symbol: "‖", detail: vertical_bar_note } + elsif line.strip.start_with?("\u00b6") + pilcrow_note = line.strip.sub(/^\¶\s*/, '') + list_of_notes << { symbol: "¶", detail: pilcrow_note } end end