— Add new check type: http-to-https (fix #61)

This commit is contained in:
Luc Didry 2024-09-26 10:11:24 +02:00
parent 175f605e35
commit 100171356b
No known key found for this signature in database
GPG key ID: EA868E12D0257E3C
7 changed files with 90 additions and 10 deletions

View file

@ -5,6 +5,7 @@
- 💄 — Correctly show results on small screens - 💄 — Correctly show results on small screens
- 📝💄 — Add opengraph tags to documentation site (#62) - 📝💄 — Add opengraph tags to documentation site (#62)
- 🔨 — Add a small web server to browse documentation when developing - 🔨 — Add a small web server to browse documentation when developing
- ✨ — Add new check type: http-to-https (#61)
## 0.4.1 ## 0.4.1

View file

@ -4,6 +4,7 @@ import json
import re import re
from datetime import datetime from datetime import datetime
from httpx import URL
from jsonpointer import resolve_pointer, JsonPointerException from jsonpointer import resolve_pointer, JsonPointerException
from argos.checks.base import ( from argos.checks.base import (
@ -55,6 +56,33 @@ class HTTPStatusIn(BaseCheck):
) )
class HTTPToHTTPS(BaseCheck):
"""Checks that the HTTP to HTTPS redirection status code is the expected one."""
config = "http-to-https"
expected_cls = ExpectedStringValue
async def run(self) -> dict:
task = self.task
url = URL(task.url).copy_with(scheme="http")
response = await self.http_client.request(method="get", url=url, timeout=60)
expected_dict = json.loads(self.expected)
expected = range(300, 400)
if "range" in expected_dict:
expected = range(expected_dict["range"][0], expected_dict["range"][1])
if "value" in expected_dict:
expected = range(expected_dict["value"], expected_dict["value"] + 1)
if "list" in expected_dict:
expected = expected_dict["list"]
return self.response(
status=response.status_code in expected,
expected=self.expected,
retrieved=response.status_code,
)
class HTTPHeadersContain(BaseCheck): class HTTPHeadersContain(BaseCheck):
"""Checks that response headers contains the expected headers """Checks that response headers contains the expected headers
(without checking their values)""" (without checking their values)"""

View file

@ -107,6 +107,21 @@ websites:
- headers-contain: - headers-contain:
- "content-encoding" - "content-encoding"
- "content-type" - "content-type"
# Check that there is a HTTP to HTTPS redirection with 3xx status code
- http-to-https: true
# Check that there is a HTTP to HTTPS redirection with 301 status code
- http-to-https: 301
# Check that there is a HTTP to HTTPS redirection with a status code
# in the provided range (stop value excluded)
- http-to-https:
start: 301
stop: 308
# Check that there is a HTTP to HTTPS redirection with a status code
# in the provided list
- http-to-https:
- 301
- 302
- 307
- path: "/admin/" - path: "/admin/"
checks: checks:
# Check that the return HTTP status is one of those # Check that the return HTTP status is one of those

View file

@ -79,12 +79,26 @@ def parse_checks(value):
if name not in available_names: if name not in available_names:
msg = f"Check should be one of f{available_names}. ({name} given)" msg = f"Check should be one of f{available_names}. ({name} given)"
raise ValueError(msg) raise ValueError(msg)
if isinstance(expected, int): if name == "http-to-https":
expected = str(expected) if isinstance(expected, int) and expected in range(300, 400):
if isinstance(expected, list): expected = json.dumps({"value": expected})
expected = json.dumps(expected) elif isinstance(expected, list):
if isinstance(expected, dict): expected = json.dumps({"list": expected})
expected = json.dumps(expected) elif (
isinstance(expected, dict)
and "start" in expected
and "stop" in expected
):
expected = json.dumps({"range": [expected["start"], expected["stop"]]})
else:
expected = json.dumps({"range": [300, 400]})
else:
if isinstance(expected, int):
expected = str(expected)
if isinstance(expected, list):
expected = json.dumps(expected)
if isinstance(expected, dict):
expected = json.dumps(expected)
return (name, expected) return (name, expected)

View file

@ -11,17 +11,18 @@ These checks are the most basic ones. They simply check that the response from t
| Check | Description | Configuration | | Check | Description | Configuration |
| --- | --- | --- | | --- | --- | --- |
| `status-is` | Check that the returned status code matches what you expect. | `status-is: "200"` | | `status-is` | Check that the returned status code matches what you expect. | <pre><code>status-is: \"200\"</code></pre> |
| `status-in` | Check that the returned status code is in the list of codes you expect. | <pre><code>status-in:<br> - 200<br> - 302</code></pre> | | `status-in` | Check that the returned status code is in the list of codes you expect. | <pre><code>status-in:<br> - 200<br> - 302</code></pre> |
| `body-contains` | Check that the returned body contains a given string. | `body-contains: "Hello world"` | | `body-contains` | Check that the returned body contains a given string. | <pre><code>body-contains: "Hello world"</code></pre> |
| `body-like` | Check that the returned body matches a given regex. | `body-like: "Hel+o w.*"` | | `body-like` | Check that the returned body matches a given regex. | <pre><code>body-like: "Hel+o w.*"</code></pre> |
| `headers-contain` | Check that the response contains the expected headers. | <pre><code>headers-contain:<br> - "content-encoding"<br> - "content-type"</code></pre> | | `headers-contain` | Check that the response contains the expected headers. | <pre><code>headers-contain:<br> - "content-encoding"<br> - "content-type"</code></pre> |
| `headers-have` | Check that the response contains the expected headers with the expected value. | <pre><code>headers-have:<br> content-encoding: "gzip"<br> content-type: "text/html"</code></pre> | | `headers-have` | Check that the response contains the expected headers with the expected value. | <pre><code>headers-have:<br> content-encoding: "gzip"<br> content-type: "text/html"</code></pre> |
| `headers-like` | Check that response headers contains the expected headers and that the values matches the provided regexes. | <pre><code>headers-like:<br> content-encoding: "gzip\|utf"<br> content-type: "text/(html\|css)"</code></pre> | | `headers-like` | Check that response headers contains the expected headers and that the values matches the provided regexes. | <pre><code>headers-like:<br> content-encoding: "gzip\|utf"<br> content-type: "text/(html\|css)"</code></pre> |
| `json-contains` | Check that JSON response contains the expected structure. | <pre><code>json-contains:<br> - /foo/bar/0<br> - /timestamp</code></pre> | | `json-contains` | Check that JSON response contains the expected structure. | <pre><code>json-contains:<br> - /foo/bar/0<br> - /timestamp</code></pre> |
| `json-has` | Check that JSON response contains the expected structure and values. | <pre><code>json-has:<br> /maintenance: false<br> /productname: "Nextcloud"</code></pre> | | `json-has` | Check that JSON response contains the expected structure and values. | <pre><code>json-has:<br> /maintenance: false<br> /productname: "Nextcloud"</code></pre> |
| `json-like` | Check that JSON response contains the expected structure and that the values matches the provided regexes. | <pre><code>json-like:<br> /productname: ".\*cloud"<br> /versionstring: "29\\\\..\*"</code></pre> | | `json-like` | Check that JSON response contains the expected structure and that the values matches the provided regexes. | <pre><code>json-like:<br> /productname: ".\*cloud"<br> /versionstring: "29\\\\..\*"</code></pre> |
| `json-is` | Check that JSON response is the exact expected JSON object. | `json-is: '{"foo": "bar", "baz": 42}'`| | `json-is` | Check that JSON response is the exact expected JSON object. | <pre><code>json-is: '{"foo": "bar", "baz": 42}'</code></pre> |
| `http-to-https` | Check that the HTTP version of the domain redirects to HTTPS. Multiple choices of configuration. | <pre><code>http-to-https: true<br>http-to-https: 301<br>http-to-https:<br> start: 301<br> stop: 308<br>http-to-https:<br> - 301<br> - 302<br> - 307</code></pre> |
```{code-block} yaml ```{code-block} yaml
--- ---
@ -37,6 +38,21 @@ caption: argos-config.yaml
- headers-contain: - headers-contain:
- "content-encoding" - "content-encoding"
- "content-type" - "content-type"
# Check that there is a HTTP to HTTPS redirection with 3xx status code
- http-to-https: true
# Check that there is a HTTP to HTTPS redirection with 301 status code
- http-to-https: 301
# Check that there is a HTTP to HTTPS redirection with a status code
# in the provided range (stop value excluded)
- http-to-https:
start: 301
stop: 308
# Check that there is a HTTP to HTTPS redirection with a status code
# in the provided list
- http-to-https:
- 301
- 302
- 307
- path: "/foobar" - path: "/foobar"
checks: checks:
- status-in: - status-in:

View file

@ -35,6 +35,8 @@ html_sidebars = {
# -- Options for HTML output ------------------------------------------------- # -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
smartquotes = False
if "CI_JOB_ID" in environ: if "CI_JOB_ID" in environ:
html_baseurl = "https://argos-monitoring.framasoft.org" html_baseurl = "https://argos-monitoring.framasoft.org"

View file

@ -41,3 +41,7 @@ If that's your case, you can implement the `finalize` method, and return some ex
# You can use the extra_arg here to determine the severity # You can use the extra_arg here to determine the severity
return Status.SUCCESS, Severity.OK return Status.SUCCESS, Severity.OK
``` ```
## Document the new check
Please, document the use of the new check in `docs/checks.md` and `argos/config-example.yaml`.