Compare commits

..

188 commits

Author SHA1 Message Date
bca1d919b2 add alertmanager formatter 2025-01-21 10:26:07 -05:00
8e1a0894f3 docs: updates to config-dist.yaml 2023-01-17 14:11:28 -05:00
86f49edf3d docs: basic readme change from the upstream version 2023-01-17 13:36:50 -05:00
fc1552304f add whitelist check to AbuseIPDB check 2022-12-08 20:29:01 -05:00
66df6e56e2 Add abuseipdb lookup to link, fix differences in version running in prod 2022-12-02 18:03:25 -05:00
05eeab7c9c add abuseipdb and crowdsec cti links for IP 2022-12-02 11:20:30 -05:00
33a650efda remove github stuff that I didn't set up for my fork 2022-11-29 22:25:51 -05:00
eb0231f4ba add pyyaml dep 2022-11-29 22:22:30 -05:00
7ff165a6f7 add crowdsec formatter 2022-11-29 22:12:42 -05:00
3c2b2d346c add package*.json 2022-11-29 22:11:08 -05:00
6e05a2a3f9 merge upstream formatter for grafana_9x 2022-11-29 22:09:11 -05:00
6781f994f9 merge upstream changes 2022-11-29 22:08:43 -05:00
Guilhem Saurel
7ba365d6e8
Merge pull request #54 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-11-29 09:03:21 +01:00
pre-commit-ci[bot]
347f639422
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.3.0 → v4.4.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.3.0...v4.4.0)
- [github.com/PyCQA/flake8: 5.0.4 → 6.0.0](https://github.com/PyCQA/flake8/compare/5.0.4...6.0.0)
2022-11-28 20:10:31 +00:00
Guilhem Saurel
e8fcb07205
Merge pull request #52 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-11-14 21:20:49 +01:00
pre-commit-ci[bot]
6cc4a7cfd9
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.2.0 → v3.2.2](https://github.com/asottile/pyupgrade/compare/v3.2.0...v3.2.2)
2022-11-14 19:25:31 +00:00
Guilhem Saurel
e963478986
Merge pull request #51 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-10-31 22:25:26 +01:00
pre-commit-ci[bot]
2ac1f123fd
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.1.0 → v3.2.0](https://github.com/asottile/pyupgrade/compare/v3.1.0...v3.2.0)
2022-10-31 19:21:12 +00:00
Guilhem Saurel
37def41cc8
Merge pull request #50 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-10-17 21:34:28 +02:00
pre-commit-ci[bot]
1dc9d79a3b
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.0.0 → v3.1.0](https://github.com/asottile/pyupgrade/compare/v3.0.0...v3.1.0)
2022-10-17 19:11:40 +00:00
Guilhem Saurel
07f3bd4714 fix ci cache 2022-10-17 10:40:09 +02:00
Guilhem Saurel
3017fb255a ci: cache poetry 2022-10-17 10:20:23 +02:00
Guilhem Saurel
97b842a20e
Merge pull request #49 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-10-10 22:10:05 +02:00
pre-commit-ci[bot]
962812758b
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.8.0 → 22.10.0](https://github.com/psf/black/compare/22.8.0...22.10.0)
- [github.com/asottile/pyupgrade: v2.38.2 → v3.0.0](https://github.com/asottile/pyupgrade/compare/v2.38.2...v3.0.0)
2022-10-10 19:35:08 +00:00
Guilhem Saurel
67ffd334e3 poetry update 2022-10-01 09:56:47 +02:00
Guilhem Saurel
5140df64c6
Merge pull request #48 from nim65s/dependabot/pip/matrix-nio-0.20.0
build(deps): bump matrix-nio from 0.18.7 to 0.20.0
2022-10-01 09:44:51 +02:00
dependabot[bot]
eb28e99aa9
build(deps): bump matrix-nio from 0.18.7 to 0.20.0
Bumps [matrix-nio](https://github.com/poljar/matrix-nio) from 0.18.7 to 0.20.0.
- [Release notes](https://github.com/poljar/matrix-nio/releases)
- [Changelog](https://github.com/poljar/matrix-nio/blob/main/CHANGELOG.md)
- [Commits](https://github.com/poljar/matrix-nio/compare/0.18.7...0.20.0)

---
updated-dependencies:
- dependency-name: matrix-nio
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-30 22:59:18 +00:00
Guilhem Saurel
c251d1c9cb
Merge pull request #47 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-09-27 11:14:27 +02:00
pre-commit-ci[bot]
8fac0e1a5d
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.38.0 → v2.38.2](https://github.com/asottile/pyupgrade/compare/v2.38.0...v2.38.2)
2022-09-26 19:09:45 +00:00
Guilhem Saurel
272a427034
Merge pull request #46 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-09-21 14:58:15 +02:00
pre-commit-ci[bot]
7915e78d87
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.37.3 → v2.38.0](https://github.com/asottile/pyupgrade/compare/v2.37.3...v2.38.0)
2022-09-19 19:10:39 +00:00
Guilhem Saurel
efdfd3a2db Release v3.5.0 2022-09-07 18:45:41 +02:00
Guilhem Saurel
5b7067f382 bump some tools 2022-09-07 18:20:59 +02:00
Guilhem Saurel
228f38f101 poetry update 2022-09-07 18:18:34 +02:00
Guilhem Saurel
1fb1a0b8f3 add #45 to CHANGELOG 2022-09-07 18:16:37 +02:00
Guilhem Saurel
880832275b
Merge pull request #45 from svenseeberg/bugfix/grafana-9x-formatting
Support Grafana v9.x messages, fixes #29
2022-09-07 18:14:41 +02:00
Sven Seeberg
e139c3a61b
Support Grafana v9.x messages, fixes #29 2022-09-07 17:45:32 +02:00
Guilhem Saurel
3288c3ff5a
Merge pull request #44 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-09-05 21:49:37 +02:00
pre-commit-ci[bot]
48b988efc0
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.6.0 → 22.8.0](https://github.com/psf/black/compare/22.6.0...22.8.0)
2022-09-05 19:11:44 +00:00
Guilhem Saurel
8f3a6a77ff
Merge pull request #43 from nim65s/dependabot/github_actions/codecov/codecov-action-3
build(deps): bump codecov/codecov-action from 1 to 3
2022-08-15 12:33:03 +02:00
dependabot[bot]
d25cfd3ba6
build(deps): bump codecov/codecov-action from 1 to 3
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 1 to 3.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v1...v3)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-15 10:28:23 +00:00
Guilhem Saurel
bc858f8bac Release v3.4.0 2022-08-12 11:50:09 +02:00
Guilhem Saurel
13c7d0a431 add changelog to urls 2022-08-12 11:47:48 +02:00
Guilhem Saurel
c82ab8c5e0 docker: setup qemu & buildx 2022-08-12 11:46:01 +02:00
Guilhem Saurel
53dd300414 update changelog 2022-08-12 11:45:42 +02:00
Guilhem Saurel
1750a1fbed
Merge pull request #42 from nim65s/dependabot/github_actions/actions/checkout-3
build(deps): bump actions/checkout from 2 to 3
2022-08-12 11:41:56 +02:00
dependabot[bot]
807a1e7b99
build(deps): bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 09:39:52 +00:00
Guilhem Saurel
8632c87d4f
Merge pull request #39 from nim65s/dependabot/github_actions/actions/setup-python-4
build(deps): bump actions/setup-python from 2 to 4
2022-08-12 11:39:43 +02:00
Guilhem Saurel
5905136919
Merge pull request #41 from nim65s/dependabot/github_actions/docker/login-action-2
build(deps): bump docker/login-action from 1 to 2
2022-08-12 11:39:30 +02:00
Guilhem Saurel
776ebb67c2
Merge pull request #40 from nim65s/dependabot/github_actions/docker/metadata-action-4
build(deps): bump docker/metadata-action from 3 to 4
2022-08-12 11:39:26 +02:00
Guilhem Saurel
0ef10cc620
Merge pull request #38 from nim65s/dependabot/github_actions/docker/build-push-action-3
build(deps): bump docker/build-push-action from 2 to 3
2022-08-12 11:39:19 +02:00
dependabot[bot]
93211f33c7
build(deps): bump docker/login-action from 1 to 2
Bumps [docker/login-action](https://github.com/docker/login-action) from 1 to 2.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 09:35:26 +00:00
dependabot[bot]
7e3983626d
build(deps): bump docker/metadata-action from 3 to 4
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 3 to 4.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Upgrade guide](https://github.com/docker/metadata-action/blob/master/UPGRADE.md)
- [Commits](https://github.com/docker/metadata-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 09:35:23 +00:00
dependabot[bot]
8127e52fc7
build(deps): bump actions/setup-python from 2 to 4
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 2 to 4.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v2...v4)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 09:35:20 +00:00
dependabot[bot]
d49bd60403
build(deps): bump docker/build-push-action from 2 to 3
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 2 to 3.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 09:35:17 +00:00
Guilhem Saurel
940cfd9bd3 add dependabot to update actions 2022-08-12 11:34:57 +02:00
Guilhem Saurel
2d17e00ec5
Merge pull request #37 from kusold/patch-1
Add linux/arm64 platform to docker builds
2022-08-12 11:32:45 +02:00
Mike Kusold
9ca48a083e
Add linux/arm64 platform to docker builds
Publishes linux/arm64 docker images.

Relevant documentation: https://github.com/docker/build-push-action/blob/master/docs/advanced/multi-platform.md
2022-08-11 23:05:47 -06:00
Guilhem Saurel
8c59d2412e
Merge pull request #36 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-08-08 21:03:23 +02:00
pre-commit-ci[bot]
d7bcc786b0
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/PyCQA/flake8: 5.0.2 → 5.0.4](https://github.com/PyCQA/flake8/compare/5.0.2...5.0.4)
2022-08-08 19:00:42 +00:00
Guilhem Saurel
a7104ac2a0 details 2022-08-05 20:27:41 +02:00
Guilhem Saurel
152c80b3ff typo 2022-08-05 20:25:00 +02:00
Guilhem Saurel
ac4e00b54a badges 2022-08-05 20:19:46 +02:00
Guilhem Saurel
760e5cbb15
Merge pull request #35 from nim65s/script
Script
2022-08-02 09:06:06 +02:00
Guilhem Saurel
2ca7201346 poetry update 2022-08-02 00:08:30 +02:00
Guilhem Saurel
6c7d015b8d add missing docstring 2022-08-01 23:59:20 +02:00
Guilhem Saurel
50e93180ee test scripts 2022-08-01 23:51:29 +02:00
Guilhem Saurel
7b9605a363 document scripts 2022-08-01 23:51:29 +02:00
Albrecht Muehlenschulte
29653fc04b adds script 2022-08-01 23:51:29 +02:00
Guilhem Saurel
0ab2507009
Merge pull request #34 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-08-01 23:39:37 +02:00
Guilhem Saurel
dd20888af4 Merge branch 'master' into pre-commit-ci-update-config 2022-08-01 23:38:08 +02:00
Guilhem Saurel
0819503d8b fix tests 2022-08-01 23:34:34 +02:00
pre-commit-ci[bot]
2fa2557076
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/PyCQA/flake8: 4.0.1 → 5.0.2](https://github.com/PyCQA/flake8/compare/4.0.1...5.0.2)
- [github.com/asottile/pyupgrade: v2.37.2 → v2.37.3](https://github.com/asottile/pyupgrade/compare/v2.37.2...v2.37.3)
2022-08-01 19:11:04 +00:00
Guilhem Saurel
52b5ff87ea
Merge pull request #33 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-07-26 00:28:18 +02:00
pre-commit-ci[bot]
36b5e85f7e
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.37.1 → v2.37.2](https://github.com/asottile/pyupgrade/compare/v2.37.1...v2.37.2)
2022-07-25 18:37:12 +00:00
Guilhem Saurel
7f2ba3d83b
Merge pull request #31 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-07-12 00:16:55 +02:00
pre-commit-ci[bot]
363f8a497d
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.34.0 → v2.37.1](https://github.com/asottile/pyupgrade/compare/v2.34.0...v2.37.1)
2022-07-11 18:33:45 +00:00
Guilhem Saurel
d53ab56661
Merge pull request #30 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-07-04 22:39:28 +02:00
pre-commit-ci[bot]
8469e679b3
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.3.0 → 22.6.0](https://github.com/psf/black/compare/22.3.0...22.6.0)
2022-07-04 18:49:48 +00:00
Guilhem Saurel
90cc262a73
Merge pull request #28 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-06-13 20:51:58 +02:00
pre-commit-ci[bot]
8e3f4e5771
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.2.0 → v4.3.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.2.0...v4.3.0)
- [github.com/asottile/pyupgrade: v2.32.1 → v2.34.0](https://github.com/asottile/pyupgrade/compare/v2.32.1...v2.34.0)
2022-06-13 18:44:41 +00:00
Guilhem Saurel
8c63736879
Merge pull request #27 from nim65s/dependabot/pip/httpx-0.23.0
Bump httpx from 0.18.2 to 0.23.0
2022-06-02 10:09:41 +02:00
dependabot[bot]
baa20e51eb
Bump httpx from 0.18.2 to 0.23.0
Bumps [httpx](https://github.com/encode/httpx) from 0.18.2 to 0.23.0.
- [Release notes](https://github.com/encode/httpx/releases)
- [Changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/httpx/compare/0.18.2...0.23.0)

---
updated-dependencies:
- dependency-name: httpx
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 23:59:44 +00:00
Guilhem Saurel
f1d2d2bd68
Merge pull request #26 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-05-10 20:03:31 +02:00
pre-commit-ci[bot]
70d85af682
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.32.0 → v2.32.1](https://github.com/asottile/pyupgrade/compare/v2.32.0...v2.32.1)
2022-05-09 18:10:56 +00:00
Guilhem Saurel
395daf4630 poetry update 2022-05-06 16:28:10 +02:00
Guilhem Saurel
8d81b7ba44
Merge pull request #24 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-04-11 20:34:44 +02:00
pre-commit-ci[bot]
36b3f6f877
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.1.0 → v4.2.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.1.0...v4.2.0)
- [github.com/asottile/pyupgrade: v2.31.1 → v2.32.0](https://github.com/asottile/pyupgrade/compare/v2.31.1...v2.32.0)
2022-04-11 18:30:34 +00:00
Guilhem Saurel
e9b3f83cd1
Merge pull request #23 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-04-04 21:50:04 +02:00
pre-commit-ci[bot]
916ddb7d18
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.1.0 → 22.3.0](https://github.com/psf/black/compare/22.1.0...22.3.0)
2022-04-04 18:04:37 +00:00
Guilhem Saurel
bdd3940066
Merge pull request #22 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-03-14 21:18:18 +01:00
pre-commit-ci[bot]
5bc8f81d8e
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.31.0 → v2.31.1](https://github.com/asottile/pyupgrade/compare/v2.31.0...v2.31.1)
2022-03-14 19:46:21 +00:00
Guilhem Saurel
11ee2ec2f4 Release v3.3.0 2022-03-04 00:36:46 +01:00
Guilhem Saurel
b66b9717e4 pyupgrade 2022-03-04 00:13:57 +01:00
Guilhem Saurel
c4e0bb76e9 poetry update 2022-03-04 00:11:35 +01:00
Guilhem Saurel
14398e4b7d changelog 2022-03-04 00:06:32 +01:00
Guilhem Saurel
42317f74d9
Merge pull request #21 from GhislainC/master
Add gitlab formatter
2022-03-04 00:05:11 +01:00
Ghislain Chatras
f6bf150c7f
Add gitlab formatter
Only for Google Chat and Microsoft Teams notification integrations
2022-03-03 19:17:40 +01:00
Guilhem Saurel
e91865f175
Merge pull request #19 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-02-10 17:25:15 +01:00
pre-commit-ci[bot]
a3607c5ee2
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.0.1 → v4.1.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.0.1...v4.1.0)
- [github.com/psf/black: 21.12b0 → 22.1.0](https://github.com/psf/black/compare/21.12b0...22.1.0)
2022-01-31 18:21:12 +00:00
f4808719b0 refactor(formatter/pingdom): build message content line-by-line
feat(formatter/pingdom): add tags to output (if set)
2022-01-12 12:08:53 -05:00
8c18c2054e refactor(formatter/buildbot): cleanup redundancy in logic 2022-01-11 22:22:20 -05:00
97e10df1a2 docs: format cleanup 2021-12-14 23:19:51 -05:00
630dc98974
docs: cleanup formatters as a table 2021-12-14 23:17:15 -05:00
7b94c80bbd docs: add buildbot and generic formatter details 2021-12-14 22:58:30 -05:00
5048ef8c4c
Merge branch 'nim65s:master' into master 2021-12-11 23:28:15 -05:00
Guilhem Saurel
ff10e58cba
Merge pull request #18 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-12-06 19:13:49 +01:00
pre-commit-ci[bot]
6032dfe836
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.11b1 → 21.12b0](https://github.com/psf/black/compare/21.11b1...21.12b0)
2021-12-06 17:55:15 +00:00
affe16c605 fix(buildbot): add else to handle non start/success statuses 2021-12-01 23:44:59 -05:00
92b6c3618b
Merge branch 'nim65s:master' into master 2021-12-01 23:37:48 -05:00
0c8c5faad0 feat(buildbot): add buildbot formatter 2021-12-01 23:36:57 -05:00
Guilhem Saurel
d799fc18a0
Merge pull request #17 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-11-25 16:05:21 +01:00
pre-commit-ci[bot]
0ac65ba895
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.10b0 → 21.11b1](https://github.com/psf/black/compare/21.10b0...21.11b1)
2021-11-22 17:47:55 +00:00
e42aa941e5 feat: add room to api config 2021-11-09 08:57:46 -05:00
778ebcdad9 feat: add slack formatter 2021-11-09 01:41:44 -05:00
e0a407acd9 feat: add generic formatter that will just return json sent 2021-11-09 01:41:26 -05:00
93f84859b4 feat: add config file handling 2021-11-05 10:01:32 -04:00
b5912a8b6c tests: add pingdom test and supporting json examples 2021-11-05 10:00:17 -04:00
d964f75c84 fix: correct missed envar for api_keys 2021-11-04 13:58:12 -04:00
a3638fdc75 update changelog 2021-11-04 13:51:42 -04:00
ab5927bfa4 feat(conf)!: allow multiple keys to be used for different endpoints 2021-11-04 13:26:54 -04:00
8e5a90ec1f refactor: clean-up 'weird' formatting 2021-11-04 00:17:24 -04:00
87ac023631 fix: correct except clauses missing exceptions 2021-11-03 23:42:44 -04:00
1ea47991e4 fix: correct exception case for invalid formatter module 2021-11-03 17:05:45 -04:00
0d92c378c4 feat: breakout formatters into their own plugin-like module to ease additonal formatters 2021-11-03 17:02:22 -04:00
d82a0ba9bd first attempt at this disaster 2021-11-03 16:12:52 -04:00
793a5e8c8c fix: correct missing colon on try 2021-11-03 15:51:05 -04:00
09fe26633f add basic functionality for pingdom formatter 2021-11-03 00:19:52 -04:00
Guilhem Saurel
afd68b791c
Merge pull request #16 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-11-02 08:38:07 +01:00
pre-commit-ci[bot]
b3004a5c8a
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.9b0 → 21.10b0](https://github.com/psf/black/compare/21.9b0...21.10b0)
2021-11-01 17:37:21 +00:00
Guilhem Saurel
2a78594861 handle M_CONSENT_NOT_GIVEN, fix #15 2021-10-12 16:23:24 +02:00
Guilhem Saurel
5a5e9655be
Merge pull request #14 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-10-11 20:41:05 +02:00
pre-commit-ci[bot]
ea91eea7ee
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/PyCQA/flake8: 3.9.2 → 4.0.1](https://github.com/PyCQA/flake8/compare/3.9.2...4.0.1)
2021-10-11 17:23:48 +00:00
Guilhem Saurel
e148dfbad9 update README after #12 2021-09-28 11:05:32 +02:00
Guilhem Saurel
b3a2e00f43 comments 2021-09-28 10:58:32 +02:00
Guilhem Saurel
d0481d741a update changelog after #12 2021-09-28 10:54:10 +02:00
Guilhem Saurel
85dd602f5c
Merge pull request #12 from bboehmke/join-room
join room before sending message
2021-09-28 10:50:27 +02:00
Guilhem Saurel
d2a3e618f4 join room: fix error code & unit tests 2021-09-28 10:39:41 +02:00
Guilhem Saurel
d9fe01c1db
Merge pull request #13 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-09-27 20:35:33 +02:00
pre-commit-ci[bot]
5d39019ef7
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.8b0 → 21.9b0](https://github.com/psf/black/compare/21.8b0...21.9b0)
2021-09-20 17:21:38 +00:00
Benjamin Böhmke
7ffa47c267 join room before sending message 2021-09-18 12:20:57 +02:00
Guilhem Saurel
624a1b2c08 grafana formatter: smaller titles 2021-09-13 17:03:57 +02:00
Guilhem Saurel
6c5b3e1358 pre-commit: drop useless checks 2021-09-12 16:00:38 +02:00
Guilhem Saurel
df2059b012 docker: use image from docker hub 2021-09-12 15:55:10 +02:00
Guilhem Saurel
d0c4cd4227 formatters: fix github format 2021-09-12 15:55:10 +02:00
Guilhem Saurel
7aa5df3871 readme: detail 2021-09-12 15:55:10 +02:00
Guilhem Saurel
e5f3d7bfbd
Merge pull request #11 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-09-12 15:54:03 +02:00
pre-commit-ci[bot]
ef79d39a9f
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.7b0 → 21.8b0](https://github.com/psf/black/compare/21.7b0...21.8b0)
2021-08-30 17:11:56 +00:00
Guilhem Saurel
179ef11ae7 readme: typo 2021-08-28 00:18:42 +02:00
Guilhem Saurel
8592be257f badges: new line 2021-08-28 00:15:41 +02:00
Guilhem Saurel
0aea63903d badges: add PyPI 2021-08-28 00:11:30 +02:00
Guilhem Saurel
df8ce523cb fix changelog 2021-08-28 00:08:56 +02:00
Guilhem Saurel
58d0e83f8f Release v3.2.1 2021-08-28 00:07:36 +02:00
Guilhem Saurel
d726db6ed2 release: push 2021-08-28 00:07:30 +02:00
Guilhem Saurel
1c00ff22f3 fix changelog 2021-08-28 00:06:38 +02:00
Guilhem Saurel
7e1be831df ci: detail 2021-08-28 00:05:20 +02:00
Guilhem Saurel
7f5c8583a1 Release v3.2.0 2021-08-27 23:59:56 +02:00
Guilhem Saurel
4928ceb91a release: details 2021-08-27 23:59:49 +02:00
Guilhem Saurel
cda8898019 tests: improve coverage 2021-08-27 23:56:56 +02:00
Guilhem Saurel
6b5d6e6e87 formatters: add github 2021-08-27 23:47:07 +02:00
Guilhem Saurel
4bcdb25c80 formatters: also get headers 2021-08-27 20:05:08 +02:00
Guilhem Saurel
ac7d1d9647 typo 2021-08-27 18:39:28 +02:00
Guilhem Saurel
9a544b8f2b detail 2021-08-27 18:33:18 +02:00
Guilhem Saurel
8f215c04fd docs: release 2021-08-27 18:33:18 +02:00
Guilhem Saurel
7f20fb7ff9 split code in utils / handler / app 2021-08-27 18:33:18 +02:00
Guilhem Saurel
2b7b79971d lint: fix pydocstyle 2021-08-27 18:15:58 +02:00
Guilhem Saurel
6aaac9149d lint: pre-commit autoupdate 2021-08-27 18:15:58 +02:00
Guilhem Saurel
eb3c795368 lint: fix line length 2021-08-27 18:15:58 +02:00
Guilhem Saurel
c03ae0a571 lint: add flake8 configuration
Black allows up to 88 characters per line.

Put this configuration into a separated file, as pyproject.toml won't do
ref. https://github.com/PyCQA/flake8/issues/234
2021-08-27 18:15:58 +02:00
Guilhem Saurel
eabb446d05 ci: release also on github 2021-08-27 18:15:55 +02:00
Guilhem Saurel
6f7d38dbd7 update test for latest synapse docker image 2021-08-27 18:14:54 +02:00
Guilhem Saurel
530f40a129 setup action to publish releases on github 2021-08-07 17:54:39 +02:00
Guilhem Saurel
528940abcc fix changelog 2021-08-07 17:54:36 +02:00
Guilhem Saurel
0ccec84eef room_id can come from url, content, or parameters 2021-08-01 13:20:03 +02:00
Guilhem Saurel
c8f6c9ec28 README: document grafana usage 2021-08-01 13:20:03 +02:00
Guilhem Saurel
c07d4bfa8d add tests for grafana formatter 2021-08-01 13:20:03 +02:00
Guilhem Saurel
2d232fe1f7 add grafana formatter
This was initially designed and implemented in #4

Co-authored-by: Sven Seeberg <mail@sven-seeberg.de>
2021-08-01 13:19:58 +02:00
Guilhem Saurel
3bebc88ee2 allow direct formatted_body
This was initially designed and implemented in #6

Co-authored-by: Gerhard Bräunlich <gerhard.braeunlich@id.ethz.ch>
2021-08-01 13:19:53 +02:00
Guilhem Saurel
fa8f9b4a51 allow "key" to be passed as a parameter
This was initially designed and implemented in #4

Co-authored-by: Sven Seeberg <mail@sven-seeberg.de>
2021-08-01 13:19:39 +02:00
Guilhem Saurel
292d77274d update "text" key to "body" 2021-07-31 11:21:29 +02:00
Guilhem Saurel
8b32c972b8 typo 2021-07-18 23:08:40 +02:00
Guilhem Saurel
c86145f794 v3.1.1 2021-07-18 22:59:49 +02:00
Guilhem Saurel
a6b192fbd7 v3.1.0 2021-07-18 22:57:09 +02:00
Guilhem Saurel
59e98b99a7
Merge pull request #10 from nim65s/devel
Publish on PyPI & Docker Hub with Github Actions
2021-07-18 22:55:19 +02:00
Guilhem Saurel
71c9c6cb0e changelog 2021-07-18 22:53:29 +02:00
Guilhem Saurel
932965c8af setup action to build/publish on PyPI 2021-07-18 22:51:41 +02:00
Guilhem Saurel
dcc73dfc81 setup action to build/publish on docker hub 2021-07-18 19:55:15 +02:00
Guilhem Saurel
fbcae98390 add metadata on PyPI through pyproject.toml 2021-07-18 19:31:46 +02:00
48 changed files with 4604 additions and 690 deletions

2
.flake8 Normal file
View file

@ -0,0 +1,2 @@
[flake8]
max-line-length = 88

View file

@ -1,8 +0,0 @@
name: Lints
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: psf/black@stable

View file

@ -1,9 +0,0 @@
name: Tests
on: [push, pull_request]
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: docker-compose -f test.yml up --exit-code-from tests
- uses: codecov/codecov-action@v1

2
.gitignore vendored
View file

@ -3,3 +3,5 @@
.mypy_cache .mypy_cache
coverage.xml coverage.xml
htmlcov htmlcov
**__pycache__
config.yaml

View file

@ -1,6 +1,6 @@
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1 rev: v4.4.0
hooks: hooks:
- id: check-added-large-files - id: check-added-large-files
- id: check-ast - id: check-ast
@ -14,7 +14,7 @@ repos:
- id: mixed-line-ending - id: mixed-line-ending
- id: trailing-whitespace - id: trailing-whitespace
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 21.6b0 rev: 22.10.0
hooks: hooks:
- id: black - id: black
language_version: python3 language_version: python3
@ -22,12 +22,15 @@ repos:
rev: 6.1.1 rev: 6.1.1
hooks: hooks:
- id: pydocstyle - id: pydocstyle
args:
- --ignore=D200,D203,D212
- repo: https://github.com/PyCQA/flake8 - repo: https://github.com/PyCQA/flake8
rev: 3.9.2 rev: 6.0.0
hooks: hooks:
- id: flake8 - id: flake8
- repo: https://gitlab.com/smop/pre-commit-hooks - repo: https://github.com/asottile/pyupgrade
rev: v1.0.0 rev: v3.2.2
hooks: hooks:
- id: check-poetry - id: pyupgrade
- id: check-gitlab-ci args:
- --py38-plus

View file

@ -6,7 +6,67 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [3.0.0] - 2021-07-18 ## [v3.5.0] - 2022-09-07
- Add formatter for grafana 9
in [#45](https://github.com/nim65s/matrix-webhook/pull/45)
by [@svenseeberg](https://github.com/svenseeberg)
## [v3.4.0] - 2022-08-12
- fix tests
- add `matrix-webhook` script
in [#25](https://github.com/nim65s/matrix-webhook/pull/25)
and [#35](https://github.com/nim65s/matrix-webhook/pull/35)
by [@a7p](https://github.com/a7p)
- publish linux/arm64 image
in [#37](https://github.com/nim65s/matrix-webhook/pull/35)
by [@kusold](https://github.com/kusold)
- update badges
- setup dependabot
- misc upgrades from poetry update, pre-commit.ci, and dependabot
## [v3.3.0] - 2022-03-04
- add pyupgrade
- add gitlab formatter for google chat & microsoft teams
in [#21](https://github.com/nim65s/matrix-webhook/pull/21)
by [@GhislainC](https://github.com/GhislainC)
- join room before sending message
in [#12](https://github.com/nim65s/matrix-webhook/pull/12)
by [@bboehmke](https://github.com/bboehmke)
- Changed --api-key and envvar API_KEY to --api-keys and API_KEYS respectively
- Changed handling of api key to use a list instead of single value
can be used
- Changed the formatters to a more plugin-based approach where each formatter is
its own <formattername>.py file in formatters directory
- Added pingdom formatter (currently handling http, dns, and tcp probe types)
## [v3.2.1] - 2021-08-28
- fix changelog
## [v3.2.0] - 2021-08-27
- add github & grafana formatters
- add formatted_body to bypass markdown with direct
[matrix-custom-HTML](https://matrix.org/docs/spec/client_server/r0.6.1#m-room-message-msgtypes)
- allow "key" to be passed as a parameter
- allow to use a sha256 HMAC hex digest with the key instead of the raw key
- allow "room_id" to be passed as a parameter or with the data
- rename "text" to "body".
- Publish releases also on github from github actions
- fix tests for recent synapse docker image
## [v3.1.1] - 2021-07-18
## [v3.1.0] - 2021-07-18
- Publish on PyPI & Docker Hub with Github Actions
in [#10](https://github.com/nim65s/matrix-webhook/pull/10)
by [@nim65s](https://github.com/nim65s)
## [v3.0.0] - 2021-07-18
- Simplify code - Simplify code
in [#1](https://github.com/nim65s/matrix-webhook/pull/1) in [#1](https://github.com/nim65s/matrix-webhook/pull/1)
@ -24,12 +84,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
in [#9](https://github.com/nim65s/matrix-webhook/pull/9) in [#9](https://github.com/nim65s/matrix-webhook/pull/9)
by [@nim65s](https://github.com/nim65s) by [@nim65s](https://github.com/nim65s)
## [2.0.0] - 2020-03-14 ## [v2.0.0] - 2020-03-14
- Update to matrix-nio & aiohttp & markdown - Update to matrix-nio & aiohttp & markdown
## [1.0.0] - 2020-02-14 ## [v1.0.0] - 2020-02-14
- First release with matrix-client & http.server - First release with matrix-client & http.server
[Unreleased]: https://github.com/nim65s/matrix-webhook/compare/v2.0.0...devel [Unreleased]: https://github.com/nim65s/matrix-webhook/compare/v3.5.0...master
[2.0.0]: https://github.com/nim65s/matrix-webhook/compare/v1.0.0...v2.0.0 [v3.5.0]: https://github.com/nim65s/matrix-webhook/compare/v3.4.0...v3.5.0
[1.0.0]: https://github.com/nim65s/matrix-webhook/releases/tag/v1.0.0 [v3.4.0]: https://github.com/nim65s/matrix-webhook/compare/v3.3.0...v3.4.0
[v3.3.0]: https://github.com/nim65s/matrix-webhook/compare/v3.2.1...v3.3.0
[v3.2.1]: https://github.com/nim65s/matrix-webhook/compare/v3.2.0...v3.2.1
[v3.2.0]: https://github.com/nim65s/matrix-webhook/compare/v3.1.1...v3.2.0
[v3.1.1]: https://github.com/nim65s/matrix-webhook/compare/v3.1.0...v3.1.1
[v3.1.0]: https://github.com/nim65s/matrix-webhook/compare/v3.0.0...v3.1.0
[v3.0.0]: https://github.com/nim65s/matrix-webhook/compare/v2.0.0...v3.0.0
[v2.0.0]: https://github.com/nim65s/matrix-webhook/compare/v1.0.0...v2.0.0
[v1.0.0]: https://github.com/nim65s/matrix-webhook/releases/tag/v1.0.0

View file

@ -1,49 +1,55 @@
# Matrix Webhook # Matrix Webhook
[![Tests](https://github.com/nim65s/matrix-webhook/actions/workflows/test.yml/badge.svg)](https://github.com/nim65s/matrix-webhook/actions/workflows/test.yml)
[![Lints](https://github.com/nim65s/matrix-webhook/actions/workflows/lint.yml/badge.svg)](https://github.com/nim65s/matrix-webhook/actions/workflows/lint.yml)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![codecov](https://codecov.io/gh/nim65s/matrix-webhook/branch/master/graph/badge.svg?token=BLGISGCYKG)](https://codecov.io/gh/nim65s/matrix-webhook)
Post a message to a matrix room with a simple HTTP POST Post a message to a matrix room with a simple HTTP POST
This is my own fork of https://github.com/nim65s/matrix-webhook
It adds a yaml configuration with multi-api key endpoints and moves the filtes
to more of a plugin-based system
## Install ## Install
``` For now, clone this repo and run `pip install .`
python3 -m pip install matrix-webhook
# OR
docker pull nim65s/matrix-webhook
```
## Start ## Start
Create a matrix user for the bot, make it join the rooms you want it to talk into, and launch it with the following Create a matrix user for the bot, and launch this app with the following arguments and/or environment variables
arguments or environment variables: (environment variables update defaults, arguments take precedence):
``` ```
matrix-webhook -h
# OR
python -m matrix_webhook -h python -m matrix_webhook -h
# OR # OR
docker run --rm -it nim65s/matrix-webhook -h docker run --rm -it nim65s/matrix-webhook -h
``` ```
``` ```
usage: python -m matrix_webhook [-h] [-H HOST] [-P PORT] [-u MATRIX_URL] -i MATRIX_ID -p MATRIX_PW -k API_KEY [-v] usage: python -m matrix_webhook [-h] [-H HOST] [-P PORT] [-u MATRIX_URL]
[-i MATRIX_ID] [-p MATRIX_PW] [-k API_KEYS]
[-c CONFIG] [-v]
Configuration for Matrix Webhook. Configuration for Matrix Webhook.
options:
optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
-H HOST, --host HOST host to listen to. Default: `''`. Environment variable: `HOST` -H HOST, --host HOST host to listen to. Default: `''`. Environment
-P PORT, --port PORT port to listed to. Default: 4785. Environment variable: `PORT` variable: `HOST`
-P PORT, --port PORT port to listed to. Default: 4785. Environment
variable: `PORT`
-u MATRIX_URL, --matrix-url MATRIX_URL -u MATRIX_URL, --matrix-url MATRIX_URL
matrix homeserver url. Default: `https://matrix.org`. Environment variable: `MATRIX_URL` matrix homeserver url. Default: `https://matrix.org`.
Environment variable: `MATRIX_URL`
-i MATRIX_ID, --matrix-id MATRIX_ID -i MATRIX_ID, --matrix-id MATRIX_ID
matrix user-id. Required. Environment variable: `MATRIX_ID` matrix user-id. Required. Environment variable:
`MATRIX_ID`
-p MATRIX_PW, --matrix-pw MATRIX_PW -p MATRIX_PW, --matrix-pw MATRIX_PW
matrix password. Required. Environment variable: `MATRIX_PW` matrix password. Required. Environment variable:
-k API_KEY, --api-key API_KEY `MATRIX_PW`
shared secret to use this service. Required. Environment variable: `API_KEY` -k API_KEYS, --api-keys API_KEYS
comma separated list of shared secrets to use this
service. Required. Environment variable: `API_KEYS`
-c CONFIG, --config CONFIG
configuration file. Default: `config.yaml`
-v, --verbose increment verbosity level -v, --verbose increment verbosity level
``` ```
@ -72,14 +78,42 @@ docker-compose up -d
## Test / Usage ## Test / Usage
``` ```
curl -d '{"text":"new contrib from toto: [44](http://radio.localhost/map/#44)", "key": "secret"}' \ curl -d '{"body":"new contrib from toto: [44](http://radio.localhost/map/#44)", "key": "secret"}' \
'http://matrixwebhook.localhost/!DPrUlnwOhBEfYwsDLh:matrix.org' 'http://matrixwebhook.localhost/!DPrUlnwOhBEfYwsDLh:matrix.org'
``` ```
(or localhost:4785 without docker) (or localhost:4785 without docker)
### Formatters
These formatters will output custom messages depending on the specific formatter. Generally to set these up, on the remote provider you would create a webhook with `https://your.webhook.domain/?formatter=<formatter columun below>&api_key=<your apikey>`
| formatter | description | key location |
| -- | - | - |
| github | for github.com | in github JSON webhook settings as `secret` |
| grafana | for grafana | in webhook URL with `api_key=<yourkey>` |
| pingdom | for pingdom.com | in webhook URL with `api_key=<yourkey>` |
| buildbot | buildbot reporter | in webhook URL with `api_key=<yourkey>` or in master.cfg credentials header as `api_key` |
| generic | returns raw JSON that was recieved. For developing additional formatter plugins | in URL with api_key=<yourkey> |
For example, if your matrix-webhook was hosted at https://webhooks.example.com, and you were setting up pingdom and you have an api_key of "123", you would use the following URL for your webhook call from pingdom:
`https://webhooks.example.com/?formatter=pingdom&api_key=123`
### For Gitlab
At a group level, Gitlab does not permit to setup webhooks. A workaround consists to use Google
Chat or Microsoft Teams notification integration with a custom URL (Gitlab does not check if the url begins with the normal url of the service).
#### Google Chat
Add a Google Chat integration with an URL ending with `?formatter=gitlab_gchat&key=API_KEY`
#### Microsoft Teams
Add a Microsoft Teams integration with an URL ending with `?formatter=gitlab_teams&key=API_KEY`
## Test room ## Test room
#matrix-webhook:tetaneutral.net](https://matrix.to/#/!DPrUlnwOhBEfYwsDLh:matrix.org?via=laas.fr&via=tetaneutral.net&via=aen.im) [#matrix-webhook:tetaneutral.net](https://matrix.to/#/!DPrUlnwOhBEfYwsDLh:matrix.org)
## Unit tests ## Unit tests

19
config-dist.yaml Normal file
View file

@ -0,0 +1,19 @@
hostname: localhost
port: 4785
# matrix-specific settings
matrix:
# URL of homeserver to connect
url: https://matrix.org
# user to connect to homserver as
id: username
# password for the user
pw: password
# keys to allow These should be random strings
# these could be generated with something like `openssl rand -hex 24`
# change these, you only need
api_keys:
RandomTextForKey: "!room_id:server.domain" # Can add a comment for what the key is used
secondRandomkey: "!a_different_room_id:server.domain"
thirdKey: #This one has no room specified, so it must be specified in the payload data or url
log:
level: debug

View file

@ -6,6 +6,7 @@ networks:
services: services:
bot: bot:
image: nim65s/matrix-webhook
build: . build: .
restart: unless-stopped restart: unless-stopped
env_file: env_file:

18
docs/release.md Normal file
View file

@ -0,0 +1,18 @@
# Publish a new release
A github actions handle the build of the release archives, and push them to PyPI and Github Releases.
To trigger it, we just need to:
1. use poetry to update the version number
2. update the changelog
3. git commit
4. git tag
5. git push
6. git push --tags
For this, an helper script is provided:
```bash
./docs/release.sh [patch|minor|major|x.y.z]
```

22
docs/release.sh Executable file
View file

@ -0,0 +1,22 @@
#!/bin/bash -eux
# ./docs/release.sh [patch|minor|major|x.y.z]
[[ $(basename "$PWD") == docs ]] && cd ..
OLD=$(poetry version -s)
poetry version "$1"
NEW=$(poetry version -s)
DATE=$(date +%Y-%m-%d)
sed -i "/^## \[Unreleased\]/a \\\n## [v$NEW] - $DATE" CHANGELOG.md
sed -i "/^\[Unreleased\]/s/$OLD/$NEW/" CHANGELOG.md
sed -i "/^\[Unreleased\]/a [v$NEW]: https://github.com/nim65s/matrix-webhook/compare/v$OLD...v$NEW" CHANGELOG.md
git add pyproject.toml CHANGELOG.md
git commit -m "Release v$NEW"
git tag -s "v$NEW" -m "Release v$NEW"
git push
git push --tags

View file

@ -1,143 +1,15 @@
""" """Matrix Webhook module entrypoint."""
Matrix Webhook.
Post a message to a matrix room with a simple HTTP POST
"""
import asyncio
import json
import logging import logging
from http import HTTPStatus
from signal import SIGINT, SIGTERM
from aiohttp import web from . import app, conf
from markdown import markdown
from nio import AsyncClient
from nio.exceptions import LocalProtocolError
from nio.responses import RoomSendError
from . import conf
ERROR_MAP = {"M_FORBIDDEN": HTTPStatus.FORBIDDEN}
CLIENT = AsyncClient(conf.MATRIX_URL, conf.MATRIX_ID)
LOGGER = logging.getLogger("matrix-webhook")
async def handler(request): def main():
""" """Start everything."""
Coroutine given to the server, st. it knows what to do with an HTTP request. log_format = "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(message)s"
logging.basicConfig(level=50 - 10 * conf.VERBOSE, format=log_format)
This one handles a POST, checks its content, and forwards it to the matrix room. app.run()
"""
LOGGER.debug(f"Handling {request=}")
data = await request.read()
try:
data = json.loads(data.decode())
except json.decoder.JSONDecodeError:
return create_json_response(HTTPStatus.BAD_REQUEST, "Invalid JSON")
if not all(key in data for key in ["text", "key"]):
return create_json_response(
HTTPStatus.BAD_REQUEST, "Missing text and/or API key property"
)
if data["key"] != conf.API_KEY:
return create_json_response(HTTPStatus.UNAUTHORIZED, "Invalid API key")
room_id = request.path[1:]
content = {
"msgtype": "m.text",
"body": data["text"],
"format": "org.matrix.custom.html",
"formatted_body": markdown(str(data["text"]), extensions=["extra"]),
}
for _ in range(10):
try:
resp = await send_room_message(room_id, content)
if isinstance(resp, RoomSendError):
if resp.status_code == "M_UNKNOWN_TOKEN":
LOGGER.warning("Reconnecting")
await CLIENT.login(conf.MATRIX_PW)
else:
return create_json_response(
ERROR_MAP[resp.status_code], resp.message
)
else:
break
except LocalProtocolError as e:
LOGGER.error(f"Send error: {e}")
LOGGER.warning("Trying again")
else:
return create_json_response(
HTTPStatus.GATEWAY_TIMEOUT, "Homeserver not responding"
)
return create_json_response(HTTPStatus.OK, "OK")
def create_json_response(status, ret):
"""Create a JSON response."""
LOGGER.debug(f"Creating json response: {status=}, {ret=}")
response_data = {"status": status, "ret": ret}
return web.json_response(response_data, status=status)
async def send_room_message(room_id, content):
"""Send a message to a room."""
LOGGER.debug(f"Sending room message in {room_id=}: {content=}")
return await CLIENT.room_send(
room_id=room_id, message_type="m.room.message", content=content
)
async def main(event):
"""
Launch main coroutine.
matrix client login & start web server
"""
LOGGER.info(f"Log in {conf.MATRIX_ID=} on {conf.MATRIX_URL=}")
await CLIENT.login(conf.MATRIX_PW)
server = web.Server(handler)
runner = web.ServerRunner(server)
await runner.setup()
LOGGER.info(f"Binding on {conf.SERVER_ADDRESS=}")
site = web.TCPSite(runner, *conf.SERVER_ADDRESS)
await site.start()
# Run until we get a shutdown request
await event.wait()
# Cleanup
await runner.cleanup()
await CLIENT.close()
def terminate(event, signal):
"""Close handling stuff."""
event.set()
asyncio.get_event_loop().remove_signal_handler(signal)
def run():
"""Launch everything."""
LOGGER.info("Starting...")
loop = asyncio.get_event_loop()
event = asyncio.Event()
for sig in (SIGINT, SIGTERM):
loop.add_signal_handler(sig, terminate, event, sig)
loop.run_until_complete(main(event))
LOGGER.info("Closing...")
loop.close()
if __name__ == "__main__": if __name__ == "__main__":
log_format = "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(message)s" main()
logging.basicConfig(level=50 - 10 * conf.VERBOSE, format=log_format)
run()

56
matrix_webhook/app.py Normal file
View file

@ -0,0 +1,56 @@
"""Matrix Webhook app."""
import asyncio
import logging
from signal import SIGINT, SIGTERM
from aiohttp import web
from . import conf, handler, utils
LOGGER = logging.getLogger("matrix_webhook.app")
async def main(event):
"""
Launch main coroutine.
matrix client login & start web server
"""
LOGGER.info(f"Log in {conf.MATRIX_ID=} on {conf.MATRIX_URL=}")
await utils.CLIENT.login(conf.MATRIX_PW)
server = web.Server(handler.matrix_webhook)
runner = web.ServerRunner(server)
await runner.setup()
LOGGER.info(f"Binding on {conf.SERVER_ADDRESS=}")
site = web.TCPSite(runner, *conf.SERVER_ADDRESS)
await site.start()
# Run until we get a shutdown request
await event.wait()
# Cleanup
await runner.cleanup()
await utils.CLIENT.close()
def terminate(event, signal):
"""Close handling stuff."""
event.set()
asyncio.get_event_loop().remove_signal_handler(signal)
def run():
"""Launch everything."""
LOGGER.info("Starting...")
loop = asyncio.get_event_loop()
event = asyncio.Event()
for sig in (SIGINT, SIGTERM):
loop.add_signal_handler(sig, terminate, event, sig)
loop.run_until_complete(main(event))
LOGGER.info("Closing...")
loop.close()

View file

@ -1,6 +1,25 @@
"""Configuration for Matrix Webhook.""" """Configuration for Matrix Webhook."""
import argparse import argparse
import os import os
import sys
import yaml
def get_numeric_log_level(log_level):
"""Return a number that will calculate to the verbosity level"""
if log_level.lower() == "debug":
return 4
elif log_level.lower() == "info":
return 3
elif log_level.lower() == "warning":
return 2
elif log_level.lower() == "error":
return 1
elif log_level.lower() == "critical":
return 0
else:
return 2
parser = argparse.ArgumentParser(description=__doc__, prog="python -m matrix_webhook") parser = argparse.ArgumentParser(description=__doc__, prog="python -m matrix_webhook")
parser.add_argument( parser.add_argument(
@ -20,47 +39,67 @@ parser.add_argument(
"-u", "-u",
"--matrix-url", "--matrix-url",
default=os.environ.get("MATRIX_URL", "https://matrix.org"), default=os.environ.get("MATRIX_URL", "https://matrix.org"),
help="matrix homeserver url. Default: `https://matrix.org`. Environment variable: `MATRIX_URL`", help="matrix homeserver url. Default: `https://matrix.org`. "
"Environment variable: `MATRIX_URL`",
) )
parser.add_argument( parser.add_argument(
"-i", "-i",
"--matrix-id", "--matrix-id",
help="matrix user-id. Required. Environment variable: `MATRIX_ID`", help="matrix user-id. Required. Environment variable: `MATRIX_ID`",
**(
{"default": os.environ["MATRIX_ID"]}
if "MATRIX_ID" in os.environ
else {"required": True}
),
) )
parser.add_argument( parser.add_argument(
"-p", "-p",
"--matrix-pw", "--matrix-pw",
help="matrix password. Required. Environment variable: `MATRIX_PW`", help="matrix password. Required. Environment variable: `MATRIX_PW`",
**(
{"default": os.environ["MATRIX_PW"]}
if "MATRIX_PW" in os.environ
else {"required": True}
),
) )
parser.add_argument( parser.add_argument(
"-k", "-k",
"--api-key", "--api-keys",
help="shared secret to use this service. Required. Environment variable: `API_KEY`", help="comma separated list of shared secrets to use this service. Required. Environment variable: `API_KEYS`",
**(
{"default": os.environ["API_KEY"]}
if "API_KEY" in os.environ
else {"required": True}
),
) )
parser.add_argument(
"-c",
"--config",
help="configuration file. Default: `config.yaml`",
)
parser.add_argument( parser.add_argument(
"-v", "--verbose", action="count", default=0, help="increment verbosity level" "-v", "--verbose", action="count", default=0, help="increment verbosity level"
) )
args = parser.parse_args() args = parser.parse_args()
SERVER_ADDRESS = (args.host, args.port) if args.config:
MATRIX_URL = args.matrix_url with open(args.config) as f:
MATRIX_ID = args.matrix_id config = yaml.safe_load(f)
MATRIX_PW = args.matrix_pw SERVER_ADDRESS = (config["hostname"], config["port"])
API_KEY = args.api_key MATRIX_URL = config["matrix"]["url"]
VERBOSE = args.verbose MATRIX_ID = config["matrix"]["id"]
MATRIX_PW = config["matrix"]["pw"]
API_KEYS = config["api_keys"]
LOG_FILE = config["log"]
VERBOSE = get_numeric_log_level(config["log"]["level"])
else:
SERVER_ADDRESS = (args.host, args.port)
MATRIX_URL = args.matrix_url
LOG_FILE = args.log
if not args.matrix_id:
print("Missing matrix user-id. Use -i or --matrix-id or specify in config.yaml")
sys.exit(1)
else:
MATRIX_ID = args.matrix_id
if not args.matrix_pw:
print(
"Missing matrix password. Use -p or --matrix-pw or specify in config.yaml"
)
sys.exit(1)
else:
MATRIX_PW = args.matrix_pw
if not args.api_keys:
print("Missing api keys. Use -k or --api-keys or specify in config.yaml")
sys.exit(1)
else:
API_KEYS = args.api_keys.split(",")
VERBOSE = args.verbose

View file

@ -0,0 +1,8 @@
def formatter(data, headers):
"""Pretty-print an alertmanager notification."""
text = ""
for alert in data['alerts']:
text += f"[{alert['status']}] - {alert['labels']['summary']}\n\n"
data["body"] = text
return data

View file

@ -0,0 +1,34 @@
from datetime import datetime
def formatter(data, headers):
"""Pretty-print a buildbot notification."""
buildid = data["buildid"]
buildstate = data["state_string"]
buildlink = data["url"]
reason = data["buildset"]["reason"]
project = data["properties"]["project"][0]
submittime = datetime.fromtimestamp(data["buildset"]["submitted_at"])
try:
if buildstate == "starting":
data["body"] = (
f"###Buildbot job #{buildid} for {project} - {buildstate}\n\n"
f"{reason}\n\n"
f"**started at** {submittime}\n\n"
f"[view details]({buildlink})"
)
elif buildstate == "build successful":
data["body"] = (
f"###Buildbot job #{buildid} for {project} - {buildstate}\n\n"
f"**completed at** {datetime.fromtimestamp(data['complete_at'])}\n\n"
f"[view details]({buildlink})"
)
else:
data["body"] = (
f"###Buildbot job #{buildid} for {project} - {buildstate}\n\n"
f"[view details]({buildlink})"
)
except Exception as error:
print(error)
return data

View file

@ -0,0 +1,36 @@
import requests
def get_abuse_confidence(ip):
"""get abuseipdb's confidence level on an ip passed in, and return that value"""
base_url = "https://api.abuseipdb.com/api/v2/check"
api_key = "YOUR API KEY"
headers = {"Key": api_key, "Accept": "application/json"}
data = {"ipAddress": ip, "maxAgeInDays": 90}
r = requests.get(base_url, headers=headers, json=data)
confidence = r.json()["data"]["abuseConfidenceScore"]
whitelist = r.json()["data"]["isWhitelisted"]
return [confidence, whitelist]
def formatter(data, headers):
"""format a message sent with crowdsec http endpoints"""
data_out = ""
for row in data["body"]:
ip = row["host"]
duration = row["duration"]
confidence, whitelisted = get_abuse_confidence(ip)
if "crowdsecurity" in row["scenario"]:
source, scenario, *_ = row["scenario"].split("/")
row[
"scenario"
] = f"[{scenario}](https://hub.crowdsec.net/author/crowdsecurity/configurations/{scenario})"
data_out += f"{ip} has been banned {duration} due to {row['scenario']}\n\n"
if whitelisted:
data_out += "**Note: AbuseIPDB has whitelisted this address\n\n"
data_out += (
f"[AbuseIPDB](https://www.abuseipdb.com/check/{row['host']})({confidence}%) | "
f"[Crowdsec](https://app.crowdsec.net/cti/{row['host']})\n\n"
)
data["body"] = data_out
return data

View file

@ -0,0 +1,4 @@
def formatter(data, headers):
"""Just dump the json data"""
data["body"] = f"{data}"
return data

View file

@ -0,0 +1,15 @@
def formatter(data, headers):
"""Pretty-print a github notification."""
# TODO: Write nice useful formatters. This is only an example.
if headers["X-GitHub-Event"] == "push":
pusher, ref, a, b, c = [
data[k] for k in ["pusher", "ref", "after", "before", "compare"]
]
pusher = f"[@{pusher['name']}](https://github.com/{pusher['name']})"
data["body"] = f"{pusher} pushed on {ref}: [{b}{a}]({c}):\n\n"
for commit in data["commits"]:
data["body"] += f"- [{commit['message']}]({commit['url']})\n"
else:
data["body"] = "notification from github"
data["digest"] = headers["X-Hub-Signature-256"].replace("sha256=", "")
return data

View file

@ -0,0 +1,12 @@
def formatter(data, headers):
"""Pretty-print a grafana notification."""
text = ""
if "title" in data:
text = "#### " + data["title"] + "\n"
if "message" in data:
text = text + data["message"] + "\n\n"
if "evalMatches" in data:
for match in data["evalMatches"]:
text = text + "* " + match["metric"] + ": " + str(match["value"]) + "\n"
data["body"] = text
return data

View file

@ -0,0 +1,9 @@
def grafana_9x(data, headers):
"""Pretty-print a Grafana newer than v9.x notification."""
text = ""
if "title" in data:
text = "#### " + data["title"] + "\n"
if "message" in data:
text = text + data["message"].replace("\n", "\n\n") + "\n\n"
data["body"] = text
return data

View file

@ -0,0 +1,64 @@
from datetime import datetime
def formatter(data, headers):
"""Pretty-print a pingdom notification."""
# JSON data formatting was obtained from https://www.pingdom.com/resources/webhooks/
# these are common to all check types
check_id = data["check_id"]
check_name = data["check_name"]
current_state = data["current_state"]
tags = data["tags"]
local_time = datetime.fromtimestamp(data["state_changed_timestamp"])
if data["check_type"].lower() == "http":
# http https or http_custom check types
try:
check_url = data["check_params"]["full_url"]
message = ""
message += f"###{check_name} is {current_state}\n\n{check_url}"
message += f" marked {current_state} at {local_time}"
message += f"[view details](https://my.pingdom.com/reports/responsetime#check={check_id})"
if tags:
message += f"\n\nTags: {tags}"
data["body"] = message
except Exception as error:
data["body"] = (
f"Error: An attempt to post from pingdom was malformed "
"(or I don't know how to handle what was sent).\n\n"
f"{repr(error)}"
)
elif data["check_type"].lower() == "dns":
# There are a bunch of values that are blanke when you do a test
# so ignore them if value is unset
try:
first_ip = data["first_probe"]["ip"]
except KeyError:
first_ip = "unknown"
try:
second_ip = data["second_probe"]["ip"]
except KeyError:
second_ip = "unknown"
try:
first_location = data["first_probe"]["location"]
except KeyError:
first_location = "unknown"
try:
second_location = data["second_probe"]["location"]
except KeyError:
second_location = "unknown"
try:
expected_ip = data["check_params"]["expected_ip"]
data["body"] = (
f"###{check_name} is {current_state}\n\n"
f"expected {expected_ip} but got:\n\n"
f" {first_ip} ({first_location})\n\n"
f" {second_ip} ({second_location})\n\n"
f" marked {current_state} at {local_time}"
f"[view details](https://my.pingdom.com/reports/responsetime#check={check_id})"
)
except Exception as error:
print(error)
return data

View file

@ -0,0 +1,5 @@
def formatter(data, headers):
""" format a message sent with slack api endpoints"""
text = data["attachments"][0]["text"]
data["body"] = f"{text}"
return data

91
matrix_webhook/handler.py Normal file
View file

@ -0,0 +1,91 @@
"""Matrix Webhook main request handler."""
import json
import logging
from http import HTTPStatus
from hmac import HMAC
import importlib
from markdown import markdown
from . import conf, utils
LOGGER = logging.getLogger("matrix_webhook.handler")
async def matrix_webhook(request):
"""
Coroutine given to the server, st. it knows what to do with an HTTP request.
This one handles a POST, checks its content, and forwards it to the matrix room.
"""
LOGGER.debug(f"Handling {request=}")
data_b = await request.read()
try:
data = json.loads(data_b.decode())
except json.decoder.JSONDecodeError:
return utils.create_json_response(HTTPStatus.BAD_REQUEST, "Invalid JSON")
# legacy naming
if "text" in data and "body" not in data:
data["body"] = data["text"]
# allow key to be passed as a parameter
if "key" in request.rel_url.query and "key" not in data:
data["key"] = request.rel_url.query["key"]
if "formatter" in request.rel_url.query:
try:
format = request.rel_url.query["formatter"]
plugin = importlib.import_module(f"matrix_webhook.formatters.{format}", "formatter")
data = plugin.formatter(data, request.headers)
except ModuleNotFoundError:
return utils.create_json_response(
HTTPStatus.BAD_REQUEST, "Unknown formatter"
)
if "room_id" in request.rel_url.query and "room_id" not in data:
data["room_id"] = request.rel_url.query["room_id"]
if "room_id" not in data:
data["room_id"] = request.path.lstrip("/")
# If we get a good SHA-256 HMAC digest,
# we can consider that the sender has the right API key
if "digest" in data:
if data["digest"] == HMAC(conf.API_KEY.encode(), data_b, "sha256").hexdigest():
data["key"] = conf.API_KEY
else: # but if there is a wrong digest, an informative error should be provided
return utils.create_json_response(
HTTPStatus.UNAUTHORIZED, "Invalid SHA-256 HMAC digest"
)
missing = []
for key in ["body", "key", "room_id"]:
if key not in data or not data[key]:
missing.append(key)
if missing:
return utils.create_json_response(
HTTPStatus.BAD_REQUEST, f"Missing {', '.join(missing)}"
)
if data["key"] not in conf.API_KEYS:
return utils.create_json_response(HTTPStatus.UNAUTHORIZED, "Invalid API key")
if "formatted_body" in data:
formatted_body = data["formatted_body"]
else:
formatted_body = markdown(str(data["body"]), extensions=["extra"])
# try to join room first -> non none response means error
resp = await utils.join_room(data["room_id"])
if resp is not None:
return resp
content = {
"msgtype": "m.text",
"body": data["body"],
"format": "org.matrix.custom.html",
"formatted_body": formatted_body,
}
return await utils.send_room_message(data["room_id"], content)

78
matrix_webhook/utils.py Normal file
View file

@ -0,0 +1,78 @@
"""Matrix Webhook utils."""
import logging
from http import HTTPStatus
from aiohttp import web
from nio import AsyncClient
from nio.exceptions import LocalProtocolError
from nio.responses import RoomSendError, JoinError
from . import conf
ERROR_MAP = {
"M_FORBIDDEN": HTTPStatus.FORBIDDEN,
"M_CONSENT_NOT_GIVEN": HTTPStatus.FORBIDDEN,
}
LOGGER = logging.getLogger("matrix_webhook.utils")
CLIENT = AsyncClient(conf.MATRIX_URL, conf.MATRIX_ID)
def error_map(resp):
"""Map response errors to HTTP status."""
if resp.status_code == "M_UNKNOWN":
# in this case, we should directly consider the HTTP status from the response
# ref. https://matrix.org/docs/spec/client_server/r0.6.1#api-standards
return resp.transport_response.status
return ERROR_MAP[resp.status_code]
def create_json_response(status, ret):
"""Create a JSON response."""
LOGGER.debug(f"Creating json response: {status=}, {ret=}")
response_data = {"status": status, "ret": ret}
return web.json_response(response_data, status=status)
async def join_room(room_id):
"""Try to join the room."""
LOGGER.debug(f"Join room {room_id=}")
for _ in range(10):
try:
resp = await CLIENT.join(room_id)
if isinstance(resp, JoinError):
if resp.status_code == "M_UNKNOWN_TOKEN":
LOGGER.warning("Reconnecting")
await CLIENT.login(conf.MATRIX_PW)
else:
return create_json_response(error_map(resp), resp.message)
else:
return None
except LocalProtocolError as e:
LOGGER.error(f"Send error: {e}")
LOGGER.warning("Trying again")
return create_json_response(HTTPStatus.GATEWAY_TIMEOUT, "Homeserver not responding")
async def send_room_message(room_id, content):
"""Send a message to a room."""
LOGGER.debug(f"Sending room message in {room_id=}: {content=}")
for _ in range(10):
try:
resp = await CLIENT.room_send(
room_id=room_id, message_type="m.room.message", content=content
)
if isinstance(resp, RoomSendError):
if resp.status_code == "M_UNKNOWN_TOKEN":
LOGGER.warning("Reconnecting")
await CLIENT.login(conf.MATRIX_PW)
else:
return create_json_response(error_map(resp), resp.message)
else:
return create_json_response(HTTPStatus.OK, "OK")
except LocalProtocolError as e:
LOGGER.error(f"Send error: {e}")
LOGGER.warning("Trying again")
return create_json_response(HTTPStatus.GATEWAY_TIMEOUT, "Homeserver not responding")

2577
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

5
package.json Normal file
View file

@ -0,0 +1,5 @@
{
"dependencies": {
"@mermaid-js/mermaid-cli": "^8.13.3"
}
}

1014
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,25 +1,36 @@
[tool.poetry] [tool.poetry]
name = "matrix-webhook" name = "matrix-webhook"
version = "3.0.0" version = "3.5.0"
description = "Post a message to a matrix room with a simple HTTP POST" description = "Post a message to a matrix room with a simple HTTP POST"
authors = ["Guilhem Saurel <guilhem.saurel@laas.fr>"] authors = ["Guilhem Saurel <guilhem.saurel@laas.fr>"]
license = "BSD-2-Clause" license = "BSD-2-Clause"
readme = "README.md"
homepage = "https://github.com/nim65s/matrix-webhook"
repository = "https://github.com/nim65s/matrix-webhook.git"
[tool.poetry.urls]
"changelog" = "https://github.com/nim65s/matrix-webhook/blob/master/CHANGELOG.md"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.9" python = "^3.8"
Markdown = "^3.3.4" Markdown = "^3.3.4"
matrix-nio = "^0.18.3" matrix-nio = ">=0.18.3,<0.21.0"
PyYAML = "^6.0"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
httpx = "^0.18.2" httpx = "^0.23.0"
coverage = "^5.5" black = "^22.8.0"
black = "^21.6b0" coverage = "^6.4.4"
pydocstyle = "^6.1.1" pydocstyle = "^6.1.1"
flake8 = "^3.9.2" flake8 = "^5.0.4"
pyupgrade = "^2.31.0"
[tool.pydocstyle] [tool.pydocstyle]
ignore = ["D203", "D204", "D212"] ignore = ["D200", "D203", "D204", "D212"]
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
[tool.poetry.scripts]
matrix-webhook = "matrix_webhook.__main__:main"

View file

@ -4,13 +4,29 @@ FROM matrixdotorg/synapse
# The config dir defaults to /data which is a volume made to keep data. # The config dir defaults to /data which is a volume made to keep data.
# Here, we want to trash those (and avoid the permission issues) by using something else # Here, we want to trash those (and avoid the permission issues) by using something else
ENV SYNAPSE_CONFIG_DIR=/srv SYNAPSE_SERVER_NAME=tests SYNAPSE_REPORT_STATS=no ENV SYNAPSE_CONFIG_DIR=/srv SYNAPSE_DATA_DIR=/srv SYNAPSE_SERVER_NAME=tests SYNAPSE_REPORT_STATS=no
# Generate configuration and keys for synapse # Generate configuration and keys for synapse
WORKDIR $SYNAPSE_CONFIG_DIR WORKDIR $SYNAPSE_CONFIG_DIR
RUN chown -R 991:991 . \ RUN chown -R 991:991 . \
&& /start.py generate \ && /start.py generate \
&& sed -i 's=/data=/srv=;s=8008=80=;s=#sup=sup=;' homeserver.yaml \ && sed -i 's=/data=/srv=;s=8008=80=;s=#sup=sup=;' homeserver.yaml \
&& echo "" >> homeserver.yaml \
&& echo "rc_message:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& echo "rc_registration:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& echo "rc_registration_token_validity:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& echo "rc_login:" >> homeserver.yaml \
&& echo " address:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& echo " account:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& echo " failed_attempts:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& echo "rc_joins:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& python -m synapse.app.homeserver --config-path homeserver.yaml --generate-keys && python -m synapse.app.homeserver --config-path homeserver.yaml --generate-keys
RUN pip install --no-cache-dir markdown matrix-nio httpx coverage RUN pip install --no-cache-dir markdown matrix-nio httpx coverage

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
{"text":"John Doe pushed to branch \u003chttps://gitlab.com/jdoe/test/commits/master|master\u003e of \u003chttps://gitlab.com/jdoe/test|John Doe / test\u003e (\u003chttps://gitlab.com/jdoe/test/compare/b76004b20503d4d506e51a670de095cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e|Compare changes\u003e)\n\u003chttps://gitlab.com/jdoe/test/-/commit/3517b06c64c9d349e2213650d6c009db0471361e|3517b06c\u003e: Merge branch 'prod' into 'master' - John Doe\n\n\u003chttps://gitlab.com/jdoe/test/-/commit/1f661795b220c5fe352f391eb8de3ac4fcc6fc1d|1f661795\u003e: Merge branch 'revert-a827b196' into 'prod' - John Doe\n\n\u003chttps://gitlab.com/jdoe/test/-/commit/b76004b20503d4d506e51a670de095cc063e4707|b76004b2\u003e: Merge branch 'revert-a827b196' into 'master' - John Doe"}

View file

@ -0,0 +1 @@
{"sections":[{"activityTitle":"John Doe pushed to branch [master](https://gitlab.com/jdoe/test/commits/master)","activitySubtitle":"in [John Doe / test](https://gitlab.com/jdoe/test)","activityText":"[Compare changes](https://gitlab.com/jdoe/test/compare/b76004b20503d4d506e51a670de095cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e)","activityImage":"https://secure.gravatar.com/avatar/80\u0026d=identicon"},{"text":"[3517b06c](https://gitlab.com/jdoe/test/-/commit/3517b06c64c9d349e2213650d6c009db0471361e): Merge branch 'prod' into 'master' - John Doe\n\n[1f661795](https://gitlab.com/jdoe/test/-/commit/1f661795b220c5fe352f391eb8de3ac4fcc6fc1d): Merge branch 'revert-a827b196' into 'prod' - John Doe\n\n[b76004b2](https://gitlab.com/jdoe/test/-/commit/b76004b20503d4d506e51a670de095cc063e4707): Merge branch 'revert-a827b196' into 'master' - John Doe"}],"title":"John Doe / test","summary":"John Doe pushed to branch [master](https://gitlab.com/jdoe/test/commits/master) of [John Doe / test](https://gitlab.com/jdoe/test) ([Compare changes](https://gitlab.com/jdoe/test/compare/b76004b20503d4d506e51a670de095cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e))"}

View file

@ -0,0 +1,22 @@
{
"dashboardId":1,
"evalMatches":[
{
"value":1,
"metric":"Count",
"tags":{}
}
],
"imageUrl":"https://grafana.com/assets/img/blog/mixed_styles.png",
"message":"Notification Message",
"orgId":1,
"panelId":2,
"ruleId":1,
"ruleName":"Panel Title alert",
"ruleUrl":"http://localhost:3000/d/hZ7BuVbWz/test-dashboard?fullscreen\u0026edit\u0026tab=alert\u0026panelId=2\u0026orgId=1",
"state":"alerting",
"tags":{
"tag name":"tag value"
},
"title":"[Alerting] Panel Title alert"
}

View file

@ -0,0 +1,41 @@
{
"receiver": "",
"status": "firing",
"alerts": [
{
"status": "firing",
"labels": {
"alertname": "TestAlert",
"instance": "Grafana"
},
"annotations": {
"summary": "Notification test"
},
"startsAt": "2022-09-07T15:00:26.722304913+02:00",
"endsAt": "0001-01-01T00:00:00Z",
"generatorURL": "",
"fingerprint": "57c6d9296de2ad39",
"silenceURL": "https://grafana.example.com/alerting/silence/new?alertmanager=grafana&matcher=alertname%3DTestAlert&matcher=instance%3DGrafana",
"dashboardURL": "",
"panelURL": "",
"valueString": "[ metric='foo' labels={instance=bar} value=10 ]"
}
],
"groupLabels": {},
"commonLabels": {
"alertname": "TestAlert",
"instance": "Grafana"
},
"commonAnnotations": {
"summary": "Notification test"
},
"externalURL": "https://grafana.example.com/",
"version": "1",
"groupKey": "{alertname=\"TestAlert\", instance=\"Grafana\"}2022-09-07 15:00:26.722304913 +0200 CEST m=+246580.963796811",
"truncatedAlerts": 0,
"orgId": 1,
"title": "[FIRING:1] (TestAlert Grafana)",
"state": "alerting",
"message": "**Firing**\n\nValue: [ metric='foo' labels={instance=bar} value=10 ]\nLabels:\n - alertname = TestAlert\n - instance = Grafana\nAnnotations:\n - summary = Notification test\nSilence: https://grafana.example.com/alerting/silence/new?alertmanager=grafana&matcher=alertname%3DTestAlert&matcher=instance%3DGrafana\n",
"key": "ak"
}

View file

@ -0,0 +1,33 @@
{
"check_id": 12345,
"check_name": "Pingdom-dns build test",
"check_type": "DNS",
"check_params": {
"hostname": "www.example.com",
"basic_auth": false,
"expected_ip": "123.4.5.6",
"ipv6": false,
"nameserver": "example.com"
},
"tags": [
"example_tag"
],
"previous_state": "UP",
"current_state": "DOWN",
"importance_level": "HIGH",
"state_changed_timestamp": 1451610061,
"state_changed_utc_time": "2016-01-01T01:01:01",
"long_description": "Long error message",
"description": "Short error message",
"first_probe": {
"ip": "123.4.5.6",
"ipv6": "2001:4800:1020:209::5",
"location": "Stockholm, Sweden"
},
"second_probe": {
"ip": "123.4.5.6",
"ipv6": "2001:4800:1020:209::5",
"location": "Austin, US",
"version": 1
}
}

View file

@ -0,0 +1,36 @@
{
"check_id": 12345,
"check_name": "Pingdom-http build test",
"check_type": "HTTP",
"check_params": {
"basic_auth": false,
"encryption": true,
"full_url": "https://www.example.com/path",
"header": "User-Agent:Pingdom.com_bot",
"hostname": "www.example.com",
"ipv6": false,
"port": 443,
"url": "/path"
},
"tags": [
"example_tag"
],
"previous_state": "UP",
"current_state": "DOWN",
"importance_level": "HIGH",
"state_changed_timestamp": 1451610061,
"state_changed_utc_time": "2016-01-01T01:01:01",
"long_description": "Long error message",
"description": "Short error message",
"first_probe": {
"ip": "123.4.5.6",
"ipv6": "2001:4800:1020:209::5",
"location": "Stockholm, Sweden"
},
"second_probe": {
"ip": "123.4.5.6",
"ipv6": "2001:4800:1020:209::5",
"location": "Austin, US",
"version": 1
}
}

View file

@ -0,0 +1,34 @@
{
"body":{
"check_id": 12345,
"check_name": "Pingdom-tcp build test",
"check_type": "PORT_TCP",
"check_params": {
"hostname": "www.example.com",
"basic_auth": false,
"ipv6": false,
"port": 80
},
"tags": [
"example_tag"
],
"previous_state": "UP",
"current_state": "DOWN",
"importance_level": "HIGH",
"state_changed_timestamp": 1451610061,
"state_changed_utc_time": "2016-01-01T01:01:01",
"long_description": "Long error message",
"description": "Short error message",
"first_probe": {
"ip": "123.4.5.6",
"ipv6": "2001:4800:1020:209::5",
"location": "Stockholm, Sweden"
},
"second_probe": {
"ip": "123.4.5.6",
"ipv6": "2001:4800:1020:209::5",
"location": "Austin, US",
"version": 1
}
}
}

View file

@ -25,19 +25,35 @@ parser.add_argument(
) )
def bot_req(req=None, key=None, room_id=None): def bot_req(
req=None,
key=None,
room_id=None,
params=None,
key_as_param=False,
room_as_parameter=False,
):
"""Bot requests boilerplate.""" """Bot requests boilerplate."""
if params is None:
params = {}
if key is not None: if key is not None:
req["key"] = key if key_as_param:
url = BOT_URL if room_id is None else f"{BOT_URL}/{room_id}" params["key"] = key
return httpx.post(url, json=req).json() else:
req["key"] = key
if room_as_parameter:
params["room_id"] = room_id
url = BOT_URL if room_id is None or room_as_parameter else f"{BOT_URL}/{room_id}"
return httpx.post(url, params=params, json=req).json()
def wait_available(url: str, key: str, timeout: int = 10) -> bool: def wait_available(url: str, key: str, timeout: int = 10) -> bool:
"""Wait until a service answer correctly or timeout.""" """Wait until a service answer correctly or timeout."""
def check_json(url: str, key: str) -> bool: def check_json(url: str, key: str) -> bool:
"""Ensure a service at a given url answers with valid json containing a certain key.""" """
Ensure a service at a given url answers with valid json including a certain key.
"""
try: try:
data = httpx.get(url).json() data = httpx.get(url).json()
return key in data return key in data
@ -88,7 +104,7 @@ def run_and_test():
srv.terminate() srv.terminate()
# TODO Check what the bot says when the server is offline # TODO Check what the bot says when the server is offline
# print(bot_req({'text': 'bye'}, KEY), {'status': 200, 'ret': 'OK'}) # print(bot_req({'data': 'bye'}, KEY), {'status': 200, 'ret': 'OK'})
LOGGER.info("Stopping the bot") LOGGER.info("Stopping the bot")
bot.terminate() bot.terminate()

130
tests/test_github.py Normal file
View file

@ -0,0 +1,130 @@
"""Test module for grafana formatter."""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, MATRIX_ID, MATRIX_PW, MATRIX_URL
SHA256 = "fd7522672889385736be8ffc86d1f8de2e15668864f49af729b5c63e5e0698c4"
def headers(sha256=SHA256, event="push"):
"""Mock headers from github webhooks."""
return {
# 'Request URL': 'https://bot.saurel.me/room?formatter=github',
# 'Request method': 'POST',
"Accept": "*/*",
"content-type": "application/json",
"User-Agent": "GitHub-Hookshot/8d33975",
"X-GitHub-Delivery": "636b9b1c-0761-11ec-8a8a-5e435c5ac4f4",
"X-GitHub-Event": event,
"X-GitHub-Hook-ID": "311845633",
"X-GitHub-Hook-Installation-Target-ID": "171114171",
"X-GitHub-Hook-Installation-Target-Type": "repository",
"X-Hub-Signature": "sha1=ea68fdfcb2f328aaa8f50d176f355e5d4fc95d94",
"X-Hub-Signature-256": f"sha256={sha256}",
}
class GithubFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Github formatter test class."""
async def test_github_notification(self):
"""Send a mock github webhook, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_github_push.json", "rb") as f:
example_github_push = f.read().strip()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={
"formatter": "github",
},
content=example_github_push,
headers=headers(event="something else"),
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(
message.formatted_body,
"<p>notification from github</p>",
)
async def test_github_push(self):
"""Send a mock github push webhook, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_github_push.json", "rb") as f:
example_github_push = f.read().strip()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={
"formatter": "github",
},
content=example_github_push,
headers=headers(),
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
before = "ac7d1d9647008145e9d0cf65d24744d0db4862b8"
after = "4bcdb25c809391baaabc264d9309059f9f48ead2"
GH = "https://github.com"
expected = f'<p><a href="{GH}/nim65s">@nim65s</a> pushed on refs/heads/devel: '
expected += f'<a href="{GH}/nim65s/matrix-webhook/compare/ac7d1d964700...'
expected += f'4bcdb25c8093">{before}{after}</a>:</p>\n<ul>\n<li>'
expected += f'<a href="{GH}/nim65s/matrix-webhook/commit/{after}">'
expected += "formatters: also get headers</a></li>\n</ul>"
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(
message.formatted_body,
expected,
)
async def test_github_wrong_digest(self):
"""Send a mock github push webhook with a wrong digest."""
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_github_push.json", "rb") as f:
example_github_push = f.read().strip()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={
"formatter": "github",
},
content=example_github_push,
headers=headers("wrong digest"),
).json(),
{"status": 401, "ret": "Invalid SHA-256 HMAC digest"},
)
await client.close()

View file

@ -0,0 +1,54 @@
"""
Test module for gitlab "google chat" formatter.
"""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, KEY, MATRIX_ID, MATRIX_PW, MATRIX_URL
class GitlabGchatFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Gitlab "google chat" formatter test class."""
async def test_gitlab_gchat_body(self):
"""Send a markdown message, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_gitlab_gchat.json") as f:
example_gitlab_gchat_request = f.read()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={"formatter": "gitlab_gchat", "key": KEY},
content=example_gitlab_gchat_request,
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(
message.body,
"John Doe pushed to branch [master](https://gitlab.com/jdoe/test/commits/m"
+ "aster) of [John Doe / test](https://gitlab.com/jdoe/test) ([Compare chan"
+ "ges](https://gitlab.com/jdoe/test/compare/b76004b20503d4d506e51a670de095"
+ "cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e))\n[3517b06c](http"
+ "s://gitlab.com/jdoe/test/-/commit/3517b06c64c9d349e2213650d6c009db047136"
+ "1e): Merge branch 'prod' into 'master' - John Doe\n\n[1f661795](https://"
+ "gitlab.com/jdoe/test/-/commit/1f661795b220c5fe352f391eb8de3ac4fcc6fc1d):"
+ " Merge branch 'revert-a827b196' into 'prod' - John Doe\n\n[b76004b2](htt"
+ "ps://gitlab.com/jdoe/test/-/commit/b76004b20503d4d506e51a670de095cc063e4"
+ "707): Merge branch 'revert-a827b196' into 'master' - John Doe",
)

View file

@ -0,0 +1,55 @@
"""
Test module for gitlab "teams" formatter.
"""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, KEY, MATRIX_ID, MATRIX_PW, MATRIX_URL
class GitlabTeamsFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Gitlab "teams" formatter test class."""
async def test_gitlab_teams_body(self):
"""Send a markdown message, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_gitlab_teams.json") as f:
example_gitlab_teams_request = f.read()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={"formatter": "gitlab_teams", "key": KEY},
content=example_gitlab_teams_request,
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(
message.body,
"John Doe pushed to branch [master](https://gitlab.com/jdoe/test/commits"
+ "/master) in [John Doe / test](https://gitlab.com/jdoe/test) \u2192 [Com"
+ "pare changes](https://gitlab.com/jdoe/test/compare/b76004b20503d4d506e5"
+ "1a670de095cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e) \n\n*"
+ " [3517b06c](https://gitlab.com/jdoe/test/-/commit/3517b06c64c9d349e2213"
+ "650d6c009db0471361e): Merge branch 'prod' into 'master' - John Doe \n*"
+ " [1f661795](https://gitlab.com/jdoe/test/-/commit/1f661795b220c5fe352f3"
+ "91eb8de3ac4fcc6fc1d): Merge branch 'revert-a827b196' into 'prod' - John"
+ " Doe \n* [b76004b2](https://gitlab.com/jdoe/test/-/commit/b76004b20503"
+ "d4d506e51a670de095cc063e4707): Merge branch 'revert-a827b196' into 'mas"
+ "ter' - John Doe",
)

46
tests/test_grafana.py Normal file
View file

@ -0,0 +1,46 @@
"""
Test module for grafana formatter.
ref https://grafana.com/docs/grafana/latest/alerting/old-alerting/notifications/#webhook
"""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, KEY, MATRIX_ID, MATRIX_PW, MATRIX_URL
class GrafanaFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Grafana formatter test class."""
async def test_grafana_body(self):
"""Send a markdown message, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_grafana.json") as f:
example_grafana_request = f.read()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={"formatter": "grafana", "key": KEY},
content=example_grafana_request,
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(
message.body,
"#### [Alerting] Panel Title alert\nNotification Message\n\n* Count: 1\n",
)

51
tests/test_grafana_9x.py Normal file
View file

@ -0,0 +1,51 @@
"""
Test module for grafana v9 formatter.
ref https://grafana.com/docs/grafana/latest/alerting/old-alerting/notifications/#webhook
"""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, MATRIX_ID, MATRIX_PW, MATRIX_URL
class Grafana9xFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Grafana formatter test class."""
async def test_grafana_body(self):
"""Send a markdown message, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_grafana_9x.json") as f:
example_grafana_request = f.read()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={"formatter": "grafana_9x"},
content=example_grafana_request,
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
expected_body = (
"#### [FIRING:1] (TestAlert Grafana)\n**Firing**\n\n\n\nValue: [ metr"
"ic='foo' labels={instance=bar} value=10 ]\n\nLabels:\n\n - alertname "
"= TestAlert\n\n - instance = Grafana\n\nAnnotations:\n\n - summary = "
"Notification test\n\nSilence: https://grafana.example.com/alerting/si"
"lence/new?alertmanager=grafana&matcher=alertname%3DTestAlert&matcher="
"instance%3DGrafana\n\n\n\n"
)
self.assertEqual(message.body, expected_body)

View file

@ -0,0 +1,51 @@
"""
Test version 9 compatibility of grafana formatter.
ref https://grafana.com/docs/grafana/latest/alerting/old-alerting/notifications/#webhook
"""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, MATRIX_ID, MATRIX_PW, MATRIX_URL
class GrafanaForwardFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Grafana formatter test class."""
async def test_grafana_body(self):
"""Send a markdown message, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_grafana_9x.json") as f:
example_grafana_request = f.read()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={"formatter": "grafana"},
content=example_grafana_request,
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
expected_body = (
"#### [FIRING:1] (TestAlert Grafana)\n**Firing**\n\n\n\nValue: [ metr"
"ic='foo' labels={instance=bar} value=10 ]\n\nLabels:\n\n - alertname "
"= TestAlert\n\n - instance = Grafana\n\nAnnotations:\n\n - summary = "
"Notification test\n\nSilence: https://grafana.example.com/alerting/si"
"lence/new?alertmanager=grafana&matcher=alertname%3DTestAlert&matcher="
"instance%3DGrafana\n\n\n\n"
)
self.assertEqual(message.body, expected_body)

44
tests/test_pingdom.py Normal file
View file

@ -0,0 +1,44 @@
"""
Test module for pingdom formatter.
"""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, KEY, MATRIX_ID, MATRIX_PW, MATRIX_URL
class PingdomFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Grafana formatter test class."""
async def test_pingdom_http_body(self):
"""Send a markdown message, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_pingdom_http.json") as f:
example_pingdom_request = f.read()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={"formatter": "pingdom", "key": KEY},
content=example_pingdom_request,
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(
message.body,
"#### [Alerting] Panel Title alert\nNotification Message\n\n* Count: 1\n",
)

View file

@ -15,19 +15,33 @@ class BotTest(unittest.IsolatedAsyncioTestCase):
self.assertEqual(bot_req(), {"status": 400, "ret": "Invalid JSON"}) self.assertEqual(bot_req(), {"status": 400, "ret": "Invalid JSON"})
self.assertEqual( self.assertEqual(
bot_req({"toto": 3}), bot_req({"toto": 3}),
{"status": 400, "ret": "Missing text and/or API key property"}, {"status": 400, "ret": "Missing body, key, room_id"},
) )
self.assertEqual( self.assertEqual(
bot_req({"text": 3, "key": None}), {"status": 401, "ret": "Invalid API key"} bot_req({"body": 3}, "wrong_key", "wrong_room"),
{"status": 401, "ret": "Invalid API key"},
) )
# TODO: if the client from matrix_webhook has olm support, this won't be a 403 from synapse,
# but a LocalProtocolError from matrix_webhook
self.assertEqual( self.assertEqual(
bot_req({"text": 3}, KEY), {"status": 403, "ret": "Unknown room"} bot_req({"body": 3}, "wrong_key", "wrong_room", key_as_param=True),
{"status": 401, "ret": "Invalid API key"},
)
self.assertEqual(
bot_req({"body": 3}, KEY, params={"formatter": "wrong_formatter"}),
{"status": 400, "ret": "Unknown formatter"},
)
# TODO: if the client from matrix_webhook has olm support,
# this won't be a 403 from synapse, but a LocalProtocolError from matrix_webhook
self.assertEqual(
bot_req({"body": 3}, KEY, "wrong_room"),
{"status": 400, "ret": "wrong_room was not legal room ID or room alias"},
)
self.assertEqual(
bot_req({"body": 3}, KEY, "wrong_room", key_as_param=True),
{"status": 400, "ret": "wrong_room was not legal room ID or room alias"},
) )
async def test_message(self): async def test_message(self):
"""Send a markdown message, and check the result.""" """Send a markdown message with the old format, and check the result."""
text = "# Hello" text = "# Hello"
messages = [] messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID) client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
@ -48,6 +62,100 @@ class BotTest(unittest.IsolatedAsyncioTestCase):
self.assertEqual(message.body, text) self.assertEqual(message.body, text)
self.assertEqual(message.formatted_body, "<h1>Hello</h1>") self.assertEqual(message.formatted_body, "<h1>Hello</h1>")
async def test_room_id_req(self):
"""Send a markdown message in a room given as data, and check the result."""
body = "# Hello"
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
self.assertEqual(
bot_req({"body": body, "room_id": room.room_id}, KEY, room.room_id),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(message.body, body)
self.assertEqual(message.formatted_body, "<h1>Hello</h1>")
async def test_room_id_parameter(self):
"""Send a markdown message in a room given as parameter."""
body = "# Hello"
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
self.assertEqual(
bot_req({"body": body}, KEY, room.room_id, room_as_parameter=True),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(message.body, body)
self.assertEqual(message.formatted_body, "<h1>Hello</h1>")
async def test_markdown_body(self):
"""Send a markdown message, and check the result."""
body = "# Hello"
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
self.assertEqual(
bot_req({"body": body}, KEY, room.room_id), {"status": 200, "ret": "OK"}
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(message.body, body)
self.assertEqual(message.formatted_body, "<h1>Hello</h1>")
async def test_formatted_body(self):
"""Send a formatted message, and check the result."""
body = "Formatted message"
formatted_body = "<del>markdown</del><strong>Formatted</strong> message"
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
self.assertEqual(
bot_req(
{"body": body, "formatted_body": formatted_body}, KEY, room.room_id
),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(message.body, body)
self.assertEqual(message.formatted_body, formatted_body)
async def test_reconnect(self): async def test_reconnect(self):
"""Check the reconnecting path.""" """Check the reconnecting path."""
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID) client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
@ -56,6 +164,6 @@ class BotTest(unittest.IsolatedAsyncioTestCase):
await client.logout(all_devices=True) await client.logout(all_devices=True)
await client.close() await client.close()
self.assertEqual( self.assertEqual(
bot_req({"text": "Re"}, KEY, room.room_id), bot_req({"body": "Re"}, KEY, room.room_id),
{"status": 200, "ret": "OK"}, {"status": 200, "ret": "OK"},
) )