feat: add environment white-list config setting and cmdline option
See description in readme for detaiös Signed-off-by: Christopher Arndt <chris@chrisarndt.de>
This commit is contained in:
		
							parent
							
								
									da31628d86
								
							
						
					
					
						commit
						fc12c00734
					
				
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
								
							| @ -52,6 +52,14 @@ steps: | |||||||
|     substtution is considered to be in Markdown format and will be rendered to |     substtution is considered to be in Markdown format and will be rendered to | ||||||
|     HTML and sent as a formatted message with `org.matrix.custom.html` format. |     HTML and sent as a formatted message with `org.matrix.custom.html` format. | ||||||
| 
 | 
 | ||||||
|  | * `pass_environment` *(default:* `DRONE_*`*)* | ||||||
|  | 
 | ||||||
|  |     Comma-separated white-list of environment variable names or name patterns. | ||||||
|  |     Patterns are shell-glob style patterns and case-sensitive. | ||||||
|  | 
 | ||||||
|  |     Only environment variables matching any of the given names or patterns will | ||||||
|  |     be available as valid placeholders in the message template. | ||||||
|  | 
 | ||||||
| * `password` | * `password` | ||||||
| 
 | 
 | ||||||
|     Password to use for authenticating the user set with `userid`. Either a |     Password to use for authenticating the user set with `userid`. Either a | ||||||
| @ -64,7 +72,8 @@ steps: | |||||||
| * `template` *(default:* `${DRONE_BUILD_STATUS}`*)* | * `template` *(default:* `${DRONE_BUILD_STATUS}`*)* | ||||||
| 
 | 
 | ||||||
|     The message template. Valid placeholders of the form `${PLACEHOLDER}` will |     The message template. Valid placeholders of the form `${PLACEHOLDER}` will | ||||||
|     be substituted with the values of the matching environment variables. |     be substituted with the values of the matching environment variables | ||||||
|  |     (subject to filtering according to the `pass_environment` setting). | ||||||
| 
 | 
 | ||||||
|     See this [reference] for environment variables available in drone.io CI |     See this [reference] for environment variables available in drone.io CI | ||||||
|     pipelines. |     pipelines. | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ Requires: | |||||||
| 
 | 
 | ||||||
| import argparse | import argparse | ||||||
| import asyncio | import asyncio | ||||||
|  | import fnmatch | ||||||
| import json | import json | ||||||
| import logging | import logging | ||||||
| import os | import os | ||||||
| @ -22,14 +23,16 @@ from nio import AsyncClient, LoginResponse | |||||||
| 
 | 
 | ||||||
| PROG = "matrixchat-notify" | PROG = "matrixchat-notify" | ||||||
| CONFIG_FILENAME = f"{PROG}-config.json" | CONFIG_FILENAME = f"{PROG}-config.json" | ||||||
| DEFAULT_TEMPLATE = "${DRONE_BUILD_STATUS}" |  | ||||||
| DEFAULT_HOMESERVER = "https://matrix.org" | DEFAULT_HOMESERVER = "https://matrix.org" | ||||||
|  | DEFAULT_PASS_ENVIRONMENT = ["DRONE_*"] | ||||||
|  | DEFAULT_TEMPLATE = "${DRONE_BUILD_STATUS}" | ||||||
| SETTINGS_KEYS = ( | SETTINGS_KEYS = ( | ||||||
|     "accesstoken", |     "accesstoken", | ||||||
|     "deviceid", |     "deviceid", | ||||||
|     "devicename", |     "devicename", | ||||||
|     "homeserver", |     "homeserver", | ||||||
|     "markdown", |     "markdown", | ||||||
|  |     "pass_environment", | ||||||
|     "password", |     "password", | ||||||
|     "roomid", |     "roomid", | ||||||
|     "template", |     "template", | ||||||
| @ -110,6 +113,38 @@ async def send_notification(config, message): | |||||||
|     await client.close() |     await client.close() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def render_message(config): | ||||||
|  |     pass_environment = config.get("pass_environment", "") | ||||||
|  | 
 | ||||||
|  |     if not isinstance(pass_environment, list): | ||||||
|  |         pass_environment = [pass_environment] | ||||||
|  | 
 | ||||||
|  |     patterns = [] | ||||||
|  |     for value in pass_environment: | ||||||
|  |         # expand any comma-separetd names/patterns | ||||||
|  |         if "," in value: | ||||||
|  |             patterns.extend([p.strip() for p in value.split(",") if p.strip()]) | ||||||
|  |         else: | ||||||
|  |             patterns.append(value) | ||||||
|  | 
 | ||||||
|  |     env_names = tuple(os.environ) | ||||||
|  |     filtered_names = set() | ||||||
|  | 
 | ||||||
|  |     for pattern in patterns: | ||||||
|  |         filtered_names.update(fnmatch.filter(env_names, pattern)) | ||||||
|  | 
 | ||||||
|  |     context = {name: os.environ[name] for name in tuple(filtered_names)} | ||||||
|  |     template = config.get("template", DEFAULT_TEMPLATE) | ||||||
|  |     return Template(template).safe_substitute(context) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def render_markdown(message): | ||||||
|  |     import markdown | ||||||
|  | 
 | ||||||
|  |     formatted = markdown.markdown(message) | ||||||
|  |     return {"formatted_body": formatted, "body": message, "format": "org.matrix.custom.html"} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def main(args=None): | def main(args=None): | ||||||
|     ap = argparse.ArgumentParser(prog=PROG, description=__doc__.splitlines()[0]) |     ap = argparse.ArgumentParser(prog=PROG, description=__doc__.splitlines()[0]) | ||||||
|     ap.add_argument( |     ap.add_argument( | ||||||
| @ -125,6 +160,17 @@ def main(args=None): | |||||||
|         action="store_true", |         action="store_true", | ||||||
|         help="Don't send notification message, only print it.", |         help="Don't send notification message, only print it.", | ||||||
|     ) |     ) | ||||||
|  |     ap.add_argument( | ||||||
|  |         "-e", | ||||||
|  |         "--pass-environment", | ||||||
|  |         nargs="*", | ||||||
|  |         help=( | ||||||
|  |             "Comma-separated white-list of environment variable names or name patterns. Only " | ||||||
|  |             "environment variables matching any of  the given names or patterns will be available " | ||||||
|  |             "as valid placeholders in the message template. " | ||||||
|  |             "Accepts shell glob patterns and may be passed more than once (default: 'DRONE_*')." | ||||||
|  |         ), | ||||||
|  |     ) | ||||||
|     ap.add_argument( |     ap.add_argument( | ||||||
|         "-m", |         "-m", | ||||||
|         "--render-markdown", |         "--render-markdown", | ||||||
| @ -150,23 +196,22 @@ def main(args=None): | |||||||
|     except Exception as exc: |     except Exception as exc: | ||||||
|         return f"Could not parse configuration: {exc}" |         return f"Could not parse configuration: {exc}" | ||||||
| 
 | 
 | ||||||
|     template = config.get("template", DEFAULT_TEMPLATE) |     if args.pass_environment is not None: | ||||||
|     message = Template(template).safe_substitute(os.environ) |         # Security feature: if any environment names/patterns are passed via -e|--pass-environment | ||||||
|  |         # options, they completely replace any given via the config or environment. | ||||||
|  |         config["pass_environment"] = args.pass_environment | ||||||
|  | 
 | ||||||
|  |     if "pass_environment" not in config: | ||||||
|  |         config["pass_environment"] = DEFAULT_PASS_ENVIRONMENT | ||||||
|  | 
 | ||||||
|  |     message = render_message(config) | ||||||
| 
 | 
 | ||||||
|     if tobool(config.get("markdown")) or args.render_markdown: |     if tobool(config.get("markdown")) or args.render_markdown: | ||||||
|         log.debug("Rendering markdown message to HTML.") |         log.debug("Rendering markdown message to HTML.") | ||||||
|         try: |         try: | ||||||
|             import markdown |             message = render_markdown(message) | ||||||
| 
 |  | ||||||
|             formatted = markdown.markdown(message) |  | ||||||
|         except:  ## noqa |         except:  ## noqa | ||||||
|             log.exception("Failed to render message with markdown.") |             log.exception("Failed to render message with markdown.") | ||||||
|             return 1 |  | ||||||
| 
 |  | ||||||
|         body = message |  | ||||||
|         message = {"formatted_body": formatted} |  | ||||||
|         message["body"] = body |  | ||||||
|         message["format"] = "org.matrix.custom.html" |  | ||||||
| 
 | 
 | ||||||
|     if not args.dry_run: |     if not args.dry_run: | ||||||
|         if not config.get("userid"): |         if not config.get("userid"): | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user