Compare commits

..

No commits in common. "fc12c00734f1edc8f0101827640b67ab1bb62738" and "d3579b6e0f3701102b8232a061ea2cc65a5b3fd1" have entirely different histories.

2 changed files with 16 additions and 68 deletions

View File

@ -52,14 +52,6 @@ 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
@ -72,8 +64,7 @@ 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.

View File

@ -10,7 +10,6 @@ Requires:
import argparse import argparse
import asyncio import asyncio
import fnmatch
import json import json
import logging import logging
import os import os
@ -23,16 +22,14 @@ from nio import AsyncClient, LoginResponse
PROG = "matrixchat-notify" PROG = "matrixchat-notify"
CONFIG_FILENAME = f"{PROG}-config.json" CONFIG_FILENAME = f"{PROG}-config.json"
DEFAULT_HOMESERVER = "https://matrix.org"
DEFAULT_PASS_ENVIRONMENT = ["DRONE_*"]
DEFAULT_TEMPLATE = "${DRONE_BUILD_STATUS}" DEFAULT_TEMPLATE = "${DRONE_BUILD_STATUS}"
DEFAULT_HOMESERVER = "https://matrix.org"
SETTINGS_KEYS = ( SETTINGS_KEYS = (
"accesstoken", "accesstoken",
"deviceid", "deviceid",
"devicename", "devicename",
"homeserver", "homeserver",
"markdown", "markdown",
"pass_environment",
"password", "password",
"roomid", "roomid",
"template", "template",
@ -113,38 +110,6 @@ 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(
@ -160,17 +125,6 @@ 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",
@ -187,7 +141,9 @@ def main(args=None):
args = ap.parse_args(args) args = ap.parse_args(args)
logging.basicConfig( logging.basicConfig(
level="DEBUG" if args.verbose else os.environ.get("PLUGIN_LOG_LEVEL", "INFO").upper(), level=getattr(
logging, "DEBUG" if args.verbose else os.environ.get("PLUGIN_LOG_LEVEL", "INFO")
),
format=os.environ.get("PLUGIN_LOG_FORMAT", "%(levelname)s: %(message)s"), format=os.environ.get("PLUGIN_LOG_FORMAT", "%(levelname)s: %(message)s"),
) )
@ -196,22 +152,23 @@ 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}"
if args.pass_environment is not None: template = config.get("template", DEFAULT_TEMPLATE)
# Security feature: if any environment names/patterns are passed via -e|--pass-environment message = Template(template).safe_substitute(os.environ)
# 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:
message = render_markdown(message) import markdown
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"):