pyrelukko 0.2.0__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyrelukko might be problematic. Click here for more details.
- pyrelukko-0.4.0/.gitlab-ci.yml +173 -0
- {pyrelukko-0.2.0 → pyrelukko-0.4.0}/PKG-INFO +7 -2
- pyrelukko-0.4.0/cicd/build-py-rf-image.sh +48 -0
- pyrelukko-0.4.0/cicd/run_docs_pages.sh +17 -0
- pyrelukko-0.4.0/cicd/run_pylint.sh +24 -0
- pyrelukko-0.4.0/cicd/run_pytest.sh +15 -0
- pyrelukko-0.4.0/cicd/run_shellcheck.sh +14 -0
- pyrelukko-0.4.0/container/Containerfile +5 -0
- pyrelukko-0.4.0/container/requirements.txt +5 -0
- pyrelukko-0.4.0/pyproject.toml +65 -0
- {pyrelukko-0.2.0 → pyrelukko-0.4.0}/src/pyrelukko/pyrelukko.py +38 -14
- pyrelukko-0.2.0/tests/conftest.py → pyrelukko-0.4.0/src/pyrelukko/testcontainers.py +26 -69
- {pyrelukko-0.2.0 → pyrelukko-0.4.0}/src/pyrelukko/version.py +1 -1
- pyrelukko-0.4.0/tests/cert/README.md +11 -0
- pyrelukko-0.4.0/tests/cert/relukko.crt +18 -0
- pyrelukko-0.4.0/tests/cert/relukko.csr +16 -0
- pyrelukko-0.4.0/tests/cert/relukko.key +28 -0
- pyrelukko-0.4.0/tests/cert/rootCA.crt +19 -0
- pyrelukko-0.4.0/tests/cert/rootCA.der +0 -0
- pyrelukko-0.4.0/tests/cert/rootCA.key +28 -0
- pyrelukko-0.4.0/tests/cert/rootCA.srl +1 -0
- pyrelukko-0.4.0/tests/conftest.py +79 -0
- {pyrelukko-0.2.0 → pyrelukko-0.4.0}/tests/test_relukko.py +61 -7
- pyrelukko-0.2.0/.pylintrc.toml +0 -9
- pyrelukko-0.2.0/pyproject.toml +0 -39
- pyrelukko-0.2.0/tests/cert/README.md +0 -8
- pyrelukko-0.2.0/tests/cert/relukko.crt +0 -21
- pyrelukko-0.2.0/tests/cert/relukko.csr +0 -16
- pyrelukko-0.2.0/tests/cert/relukko.der +0 -0
- pyrelukko-0.2.0/tests/cert/relukko.key +0 -28
- pyrelukko-0.2.0/tests/cert/rootCA.crt +0 -21
- pyrelukko-0.2.0/tests/cert/rootCA.der +0 -0
- pyrelukko-0.2.0/tests/cert/rootCA.key +0 -28
- pyrelukko-0.2.0/tests/cert/rootCA.srl +0 -1
- pyrelukko-0.2.0/tests/initdb.d/20240930160154_init.up.sql +0 -19
- {pyrelukko-0.2.0 → pyrelukko-0.4.0}/LICENSE +0 -0
- {pyrelukko-0.2.0 → pyrelukko-0.4.0}/README.md +0 -0
- {pyrelukko-0.2.0 → pyrelukko-0.4.0}/src/pyrelukko/__init__.py +0 -0
- {pyrelukko-0.2.0 → pyrelukko-0.4.0}/src/pyrelukko/retry.py +0 -0
- /pyrelukko-0.2.0/tests/cert/47615cfb.0 → /pyrelukko-0.4.0/tests/cert/5d868fca.0 +0 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
variables:
|
|
2
|
+
FF_TIMESTAMPS: true
|
|
3
|
+
BUILD_IMAGE:
|
|
4
|
+
description: Used in rules, if "true" and web triggered it builds the image!
|
|
5
|
+
value: "false"
|
|
6
|
+
options:
|
|
7
|
+
- "false"
|
|
8
|
+
- "true"
|
|
9
|
+
IMAGE_NAME: py-rf-image
|
|
10
|
+
IMAGE_TAG:
|
|
11
|
+
description: >-
|
|
12
|
+
The "tag" added to the image name for the test / lint image.
|
|
13
|
+
Remove this when you trigger by hand an image build and want it to use
|
|
14
|
+
the new built image with Git short sha tag (X icon on the right)!
|
|
15
|
+
value: "latest"
|
|
16
|
+
RUN_PYTEST:
|
|
17
|
+
description: Used in rules, if "true" and web triggered run the pytests.
|
|
18
|
+
value: "false"
|
|
19
|
+
options:
|
|
20
|
+
- "false"
|
|
21
|
+
- "true"
|
|
22
|
+
RELUKKO_HOSTNAME: relukko
|
|
23
|
+
RELUKKO_BIND_PORT: 3000
|
|
24
|
+
RELUKKO_API_KEY: "somerandomkey"
|
|
25
|
+
POSTGRES_USER: relukko
|
|
26
|
+
POSTGRES_PASSWORD: okkuler
|
|
27
|
+
POSTGRES_DB: relukko
|
|
28
|
+
POSTGRES_HOSTNAME: postgres
|
|
29
|
+
# RUN_DOCS_PUBLISH:
|
|
30
|
+
# description: >-
|
|
31
|
+
# Used in rules, if "true" and web triggered it generates the docs and
|
|
32
|
+
# publishes them!
|
|
33
|
+
# value: "false"
|
|
34
|
+
# options:
|
|
35
|
+
# - "false"
|
|
36
|
+
# - "true"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
build-py-rf-image:
|
|
40
|
+
stage: build
|
|
41
|
+
image: docker:25
|
|
42
|
+
services:
|
|
43
|
+
- name: docker:25-dind
|
|
44
|
+
alias: docker
|
|
45
|
+
before_script:
|
|
46
|
+
- docker info
|
|
47
|
+
before_script:
|
|
48
|
+
- echo "Login to Gitlab container registry"
|
|
49
|
+
- echo "$CI_REGISTRY_PASSWORD" | docker login --username $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
|
|
50
|
+
script:
|
|
51
|
+
- echo "Build container image..."
|
|
52
|
+
- ./cicd/build-py-rf-image.sh
|
|
53
|
+
- echo "Export IMAGE_TAG var to next stage!"
|
|
54
|
+
- echo "IMAGE_TAG=${CI_COMMIT_SHORT_SHA}" > image_tag.env
|
|
55
|
+
- echo "Build complete."
|
|
56
|
+
artifacts:
|
|
57
|
+
reports:
|
|
58
|
+
dotenv: image_tag.env
|
|
59
|
+
rules:
|
|
60
|
+
- if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
61
|
+
changes:
|
|
62
|
+
- .gitlab-ci.yml
|
|
63
|
+
- cicd/build-py-rf-image.sh
|
|
64
|
+
- container/**/*
|
|
65
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
|
|
66
|
+
changes:
|
|
67
|
+
- .gitlab-ci.yml
|
|
68
|
+
- cicd/build-py-rf-image.sh
|
|
69
|
+
- container/**/*
|
|
70
|
+
- if: $CI_PIPELINE_SOURCE == "web" && $BUILD_IMAGE == "true"
|
|
71
|
+
when: always
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
run-pylint:
|
|
75
|
+
stage: test
|
|
76
|
+
image: "${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${IMAGE_TAG}"
|
|
77
|
+
rules:
|
|
78
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
|
|
79
|
+
changes:
|
|
80
|
+
- src/**/*.py
|
|
81
|
+
- if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
82
|
+
changes:
|
|
83
|
+
- src/**/*.py
|
|
84
|
+
before_script:
|
|
85
|
+
- echo "Running PyLint."
|
|
86
|
+
script:
|
|
87
|
+
- ./cicd/run_pylint.sh
|
|
88
|
+
artifacts:
|
|
89
|
+
when: always
|
|
90
|
+
expire_in: 2 week
|
|
91
|
+
paths:
|
|
92
|
+
- pylint.out.*
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
run-pytest:
|
|
96
|
+
stage: test
|
|
97
|
+
services:
|
|
98
|
+
- name: postgres:16
|
|
99
|
+
alias: postgres
|
|
100
|
+
- name: registry.gitlab.com/relukko/relukko:latest
|
|
101
|
+
alias: relukko
|
|
102
|
+
variables:
|
|
103
|
+
DATABASE_URL: "postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}"
|
|
104
|
+
RELUKKO_USER: "relukko"
|
|
105
|
+
RELUKKO_PASSWORD: "relukko"
|
|
106
|
+
RELUKKO_BIND_ADDR: "0.0.0.0"
|
|
107
|
+
HEALTHCHECK_TCP_PORT: "${RELUKKO_BIND_PORT}"
|
|
108
|
+
variables:
|
|
109
|
+
FF_NETWORK_PER_BUILD: 1
|
|
110
|
+
CI_HAS_RELUKKO: true
|
|
111
|
+
CI_RELUKKO_BASE_URL: "http://${RELUKKO_HOSTNAME}:${RELUKKO_BIND_PORT}"
|
|
112
|
+
CI_RELUKKO_API_KEY: "${RELUKKO_API_KEY}"
|
|
113
|
+
parallel:
|
|
114
|
+
matrix:
|
|
115
|
+
- PIPELINE_PY_VERSION: ['3.11', '3.12', '3.13']
|
|
116
|
+
image: "registry.gitlab.com/relukko/py-tox-images/py-$PIPELINE_PY_VERSION-tox"
|
|
117
|
+
rules:
|
|
118
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
|
|
119
|
+
changes:
|
|
120
|
+
- src/**/*.py
|
|
121
|
+
- tests/test_*.py
|
|
122
|
+
- tests/conftest.py
|
|
123
|
+
- if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
124
|
+
changes:
|
|
125
|
+
- src/**/*.py
|
|
126
|
+
- tests/test_*.py
|
|
127
|
+
- tests/conftest.py
|
|
128
|
+
- if: $CI_PIPELINE_SOURCE == "web" && $RUN_PYTEST == "true"
|
|
129
|
+
when: always
|
|
130
|
+
before_script:
|
|
131
|
+
- echo "Running PyTest."
|
|
132
|
+
script:
|
|
133
|
+
- ./cicd/run_pytest.sh
|
|
134
|
+
artifacts:
|
|
135
|
+
when: always
|
|
136
|
+
expire_in: 2 week
|
|
137
|
+
paths:
|
|
138
|
+
- pytest-junit.xml
|
|
139
|
+
reports:
|
|
140
|
+
junit: pytest-junit.xml
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
run-shellcheck:
|
|
144
|
+
stage: test
|
|
145
|
+
image: "${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${IMAGE_TAG}"
|
|
146
|
+
rules:
|
|
147
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
|
|
148
|
+
changes:
|
|
149
|
+
- cicd/*.sh
|
|
150
|
+
- if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
151
|
+
changes:
|
|
152
|
+
- cicd/*.sh
|
|
153
|
+
before_script:
|
|
154
|
+
- echo "Running ShellCheck."
|
|
155
|
+
script:
|
|
156
|
+
- ./cicd/run_shellcheck.sh
|
|
157
|
+
|
|
158
|
+
# pages:
|
|
159
|
+
# stage: deploy
|
|
160
|
+
# image: "${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${IMAGE_TAG}"
|
|
161
|
+
# rules:
|
|
162
|
+
# - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
163
|
+
# changes:
|
|
164
|
+
# - src/**/*.py
|
|
165
|
+
# - if: $CI_PIPELINE_SOURCE == "web" && $RUN_DOCS_PUBLISH == "true"
|
|
166
|
+
# when: always
|
|
167
|
+
# before_script:
|
|
168
|
+
# - echo "Running Docs generation and publishing..."
|
|
169
|
+
# script:
|
|
170
|
+
# - ./cicd/run_docs_pages.sh
|
|
171
|
+
# artifacts:
|
|
172
|
+
# paths:
|
|
173
|
+
# - public
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: pyrelukko
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Relukko client.
|
|
5
5
|
Author-email: Reto Zingg <g.d0b3rm4n@gmail.com>
|
|
6
|
-
Requires-Python: >=3.
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
Classifier: Development Status :: 3 - Alpha
|
|
9
9
|
Classifier: Intended Audience :: Developers
|
|
10
10
|
Classifier: License :: OSI Approved :: MIT License
|
|
11
11
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
12
12
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
17
|
Requires-Dist: requests >=2.32.3
|
|
18
|
+
Requires-Dist: websockets >= 13.1
|
|
14
19
|
Project-URL: Homepage, https://gitlab.com/relukko/pyrelukko
|
|
15
20
|
Project-URL: Issues, https://gitlab.com/relukko/pyrelukko/-/issues
|
|
16
21
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
|
|
6
|
+
REPO_DIR="${SCRIPT_DIR}/.."
|
|
7
|
+
CONTAINER_DIR="${REPO_DIR}/container"
|
|
8
|
+
CONTAINER_CMD="docker"
|
|
9
|
+
|
|
10
|
+
# IMAGE_NAME should normally come from .gitlab-ci.yml file,
|
|
11
|
+
# set default for local usage.
|
|
12
|
+
if [ -z "${IMAGE_NAME+x}" ]; then
|
|
13
|
+
IMAGE_NAME=py-rf-image-local
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
cd "${CONTAINER_DIR}" || exit
|
|
17
|
+
|
|
18
|
+
${CONTAINER_CMD} build -t "${IMAGE_NAME}:latest" --file Containerfile .
|
|
19
|
+
|
|
20
|
+
${CONTAINER_CMD} images
|
|
21
|
+
|
|
22
|
+
if [ -n "${CI_REGISTRY_IMAGE}" ]; then
|
|
23
|
+
# In Gitlab
|
|
24
|
+
|
|
25
|
+
# Tag with Git commit short sha and push
|
|
26
|
+
IMAGE_WITH_GIT_SHA="${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}"
|
|
27
|
+
echo "IMAGE_WITH_GIT_SHA: ${IMAGE_WITH_GIT_SHA}"
|
|
28
|
+
|
|
29
|
+
${CONTAINER_CMD} tag "${IMAGE_NAME}:latest" "${IMAGE_WITH_GIT_SHA}"
|
|
30
|
+
${CONTAINER_CMD} push "${IMAGE_WITH_GIT_SHA}"
|
|
31
|
+
|
|
32
|
+
if [ "${CI_COMMIT_BRANCH}" = "${CI_DEFAULT_BRANCH}" ]; then
|
|
33
|
+
# We run in default branch, also tag with latest
|
|
34
|
+
# Tag with "latest" (overwrites last 'latest' in registry) and push
|
|
35
|
+
IMAGE_WITH_LATEST="${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:latest"
|
|
36
|
+
|
|
37
|
+
echo "Tag image with as 'latest': ${IMAGE_WITH_LATEST}"
|
|
38
|
+
|
|
39
|
+
${CONTAINER_CMD} tag "${IMAGE_NAME}:latest" "${IMAGE_WITH_LATEST}"
|
|
40
|
+
${CONTAINER_CMD} push "${IMAGE_WITH_LATEST}"
|
|
41
|
+
fi
|
|
42
|
+
else
|
|
43
|
+
echo "Runs locally, no pushing!"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
cd -
|
|
47
|
+
|
|
48
|
+
# vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
|
|
4
|
+
REPO_DIR="${SCRIPT_DIR}/.."
|
|
5
|
+
PUBLIC_DIR="${REPO_DIR}/public"
|
|
6
|
+
|
|
7
|
+
# Main script execution
|
|
8
|
+
main() {
|
|
9
|
+
mkdir -p "${PUBLIC_DIR}"
|
|
10
|
+
# libdoc --pythonpath ./src Relukko "${PUBLIC_DIR}/index.html"
|
|
11
|
+
echo "Not Implemented yet"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
# Execute the main function
|
|
15
|
+
main
|
|
16
|
+
|
|
17
|
+
# vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
|
|
4
|
+
REPO_DIR="${SCRIPT_DIR}/.."
|
|
5
|
+
|
|
6
|
+
# Main script execution
|
|
7
|
+
main() {
|
|
8
|
+
pylint --verbose \
|
|
9
|
+
--rcfile "${REPO_DIR}/pyproject.toml" \
|
|
10
|
+
--output-format=json:pylint.out.json,parseable:pylint.out.txt,text \
|
|
11
|
+
"${REPO_DIR}"
|
|
12
|
+
pylint_exit_code=$?
|
|
13
|
+
|
|
14
|
+
pylint-json2html \
|
|
15
|
+
-o "${REPO_DIR}/pylint.out.html" \
|
|
16
|
+
"${REPO_DIR}/pylint.out.json"
|
|
17
|
+
|
|
18
|
+
return ${pylint_exit_code}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Execute the main function
|
|
22
|
+
main
|
|
23
|
+
|
|
24
|
+
# vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
|
|
4
|
+
# REPO_DIR="${SCRIPT_DIR}/.."
|
|
5
|
+
|
|
6
|
+
# Main script execution
|
|
7
|
+
main() {
|
|
8
|
+
# pytest --junit-xml "${REPO_DIR}/pytest-junit.xml"
|
|
9
|
+
tox run --skip-missing-interpreters
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
# Execute the main function
|
|
13
|
+
main
|
|
14
|
+
|
|
15
|
+
# vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
|
|
4
|
+
REPO_DIR="${SCRIPT_DIR}/.."
|
|
5
|
+
|
|
6
|
+
# Main script execution
|
|
7
|
+
main() {
|
|
8
|
+
shellcheck "${REPO_DIR}"/cicd/*.sh
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
# Execute the main function
|
|
12
|
+
main
|
|
13
|
+
|
|
14
|
+
# vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pyrelukko"
|
|
3
|
+
authors = [
|
|
4
|
+
{name = "Reto Zingg", email = "g.d0b3rm4n@gmail.com"},
|
|
5
|
+
]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
|
|
8
|
+
# https://pypi.org/pypi?%3Aaction=list_classifiers
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Development Status :: 3 - Alpha",
|
|
11
|
+
"Intended Audience :: Developers",
|
|
12
|
+
"License :: OSI Approved :: MIT License",
|
|
13
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
14
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Programming Language :: Python :: 3.14",
|
|
19
|
+
]
|
|
20
|
+
requires-python = ">=3.10"
|
|
21
|
+
dynamic = ["version", "description"]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"requests >=2.32.3",
|
|
24
|
+
"websockets >= 13.1",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[tool.flit.sdist]
|
|
28
|
+
exclude = [".gitignore", "demo.py"]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://gitlab.com/relukko/pyrelukko"
|
|
32
|
+
Issues = "https://gitlab.com/relukko/pyrelukko/-/issues"
|
|
33
|
+
|
|
34
|
+
[build-system]
|
|
35
|
+
requires = ["flit_core >=3.2,<4", "semantic-version >= 2.10"]
|
|
36
|
+
build-backend = "flit_core.buildapi"
|
|
37
|
+
|
|
38
|
+
[tool.pytest.ini_options]
|
|
39
|
+
testpaths = [
|
|
40
|
+
"tests",
|
|
41
|
+
]
|
|
42
|
+
pythonpath = [
|
|
43
|
+
"src",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[tool.tox]
|
|
47
|
+
requires = ["tox>=4.23"]
|
|
48
|
+
env_list = ["3.11", "3.12", "3.13"]
|
|
49
|
+
|
|
50
|
+
[tool.tox.env_run_base]
|
|
51
|
+
description = "Run test under {base_python}"
|
|
52
|
+
commands = [["pytest", "--junit-xml", "pytest-junit.xml"]]
|
|
53
|
+
deps = ["httpx", "pytest", "testcontainers"]
|
|
54
|
+
# set_env = { VIRTUALENV_DISCOVERY = "pyenv" }
|
|
55
|
+
pass_env = [ "TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE", "DOCKER_HOST", "CI_HAS_RELUKKO", "CI_RELUKKO_*" ]
|
|
56
|
+
|
|
57
|
+
[tool.pylint.main]
|
|
58
|
+
# Files or directories to be skipped. They should be base names, not paths.
|
|
59
|
+
ignore = ["LICENSE", "pyproject.toml", "version.py",
|
|
60
|
+
"README.md", "demo.py", "conftest.py", ".tox"]
|
|
61
|
+
|
|
62
|
+
# Files or directories matching the regular expression patterns are skipped. The
|
|
63
|
+
# regex matches against base names, not paths. The default value ignores Emacs
|
|
64
|
+
# file locks
|
|
65
|
+
ignore-patterns = ["^\\.#", "^test_"]
|
|
@@ -33,9 +33,18 @@ RETRY_KWARGS = [
|
|
|
33
33
|
'delay',
|
|
34
34
|
'backoff',
|
|
35
35
|
'max_delay',
|
|
36
|
-
'exceptions'
|
|
36
|
+
'exceptions',
|
|
37
37
|
]
|
|
38
38
|
|
|
39
|
+
OWN_KWARGS = [
|
|
40
|
+
'acquire_wait_for_timeout',
|
|
41
|
+
'acquire_modulo',
|
|
42
|
+
'ws_ping_interval',
|
|
43
|
+
'ws_ping_timeout',
|
|
44
|
+
'ws_wait_for_timeout',
|
|
45
|
+
]
|
|
46
|
+
OWN_KWARGS.extend(RETRY_KWARGS)
|
|
47
|
+
|
|
39
48
|
logger = logging.getLogger(__name__)
|
|
40
49
|
|
|
41
50
|
|
|
@@ -66,7 +75,12 @@ class RelukkoClient:
|
|
|
66
75
|
)
|
|
67
76
|
self._setup_session(api_key, **kwargs)
|
|
68
77
|
self._setup_http_adapters_retry(**kwargs)
|
|
69
|
-
self.
|
|
78
|
+
self.ws_wait_for_timeout = 2
|
|
79
|
+
self.ws_ping_interval = 60
|
|
80
|
+
self.ws_ping_timeout = 20
|
|
81
|
+
self.acquire_wait_for_timeout = 2
|
|
82
|
+
self.acquire_modulo = 100
|
|
83
|
+
self._setup_pyrelukko_kwargs(**kwargs)
|
|
70
84
|
|
|
71
85
|
self.base_url = self._setup_base_url(base_url)
|
|
72
86
|
self.ws_url = self._setup_ws_url(str(self.base_url))
|
|
@@ -90,10 +104,10 @@ class RelukkoClient:
|
|
|
90
104
|
self.base_url = self._setup_base_url(base_url or self.base_url)
|
|
91
105
|
self.ws_url = self._setup_ws_url(str(self.base_url))
|
|
92
106
|
self._setup_ssl_ctx(**kwargs)
|
|
93
|
-
self.
|
|
107
|
+
self._setup_pyrelukko_kwargs(**kwargs)
|
|
94
108
|
|
|
95
|
-
def
|
|
96
|
-
for kwarg in
|
|
109
|
+
def _setup_pyrelukko_kwargs(self, **kwargs):
|
|
110
|
+
for kwarg in OWN_KWARGS:
|
|
97
111
|
setattr(
|
|
98
112
|
self,
|
|
99
113
|
kwarg,
|
|
@@ -151,7 +165,7 @@ class RelukkoClient:
|
|
|
151
165
|
|
|
152
166
|
def _setup_ws_url(self, ws_url: str) -> Url:
|
|
153
167
|
url = ws_url.replace("http", "ws", 1)
|
|
154
|
-
return parse_url(f"{url}/
|
|
168
|
+
return parse_url(f"{url}/ws/broadcast")
|
|
155
169
|
|
|
156
170
|
def _setup_base_url(self, base_url: Union[Url, str]) -> Url:
|
|
157
171
|
if isinstance(base_url, str):
|
|
@@ -174,14 +188,17 @@ class RelukkoClient:
|
|
|
174
188
|
additional_headers=additional_headers,
|
|
175
189
|
ssl=self.ssl_ctx,
|
|
176
190
|
logger=logger,
|
|
191
|
+
ping_interval=self.ws_ping_interval,
|
|
192
|
+
ping_timeout=self.ws_ping_timeout,
|
|
177
193
|
) as websocket:
|
|
178
194
|
while self.ws_running.is_set():
|
|
179
195
|
try:
|
|
180
|
-
ws_message = await asyncio.wait_for(
|
|
196
|
+
ws_message = await asyncio.wait_for(
|
|
197
|
+
websocket.recv(), timeout=self.ws_wait_for_timeout)
|
|
181
198
|
if ws_message:
|
|
182
199
|
logger.debug("Received message: '%s'", ws_message)
|
|
183
200
|
msg: Dict = json.loads(ws_message)
|
|
184
|
-
if msg.get('
|
|
201
|
+
if msg.get('deleted'):
|
|
185
202
|
# Signal the HTTP thread to wake up
|
|
186
203
|
self.message_received.set()
|
|
187
204
|
except TimeoutError:
|
|
@@ -199,19 +216,25 @@ class RelukkoClient:
|
|
|
199
216
|
"""
|
|
200
217
|
|
|
201
218
|
start_time = time.time()
|
|
202
|
-
|
|
219
|
+
loop_counter = 0
|
|
220
|
+
got_message = False
|
|
221
|
+
res = None
|
|
203
222
|
while True:
|
|
204
223
|
elapsed_time = time.time() - start_time
|
|
205
224
|
if elapsed_time > max_run_time:
|
|
206
225
|
self.ws_running.clear()
|
|
207
226
|
_thread_store.insert(0, None)
|
|
208
227
|
return
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
228
|
+
# If self.message_recieved is True try to get lock ASAP!
|
|
229
|
+
# Otherwise only in every Xth run in case websocket broke.
|
|
230
|
+
if got_message or loop_counter % self.acquire_modulo == 0:
|
|
231
|
+
res = self._make_request(
|
|
232
|
+
url=url, method="POST", payload=payload)
|
|
233
|
+
loop_counter += 1
|
|
212
234
|
if res is None:
|
|
213
235
|
# Conflict 409
|
|
214
|
-
self.message_received.wait(
|
|
236
|
+
got_message = self.message_received.wait(
|
|
237
|
+
timeout=self.acquire_wait_for_timeout)
|
|
215
238
|
self.message_received.clear()
|
|
216
239
|
else:
|
|
217
240
|
_thread_store.insert(0, res)
|
|
@@ -277,7 +300,8 @@ class RelukkoClient:
|
|
|
277
300
|
|
|
278
301
|
thread_store = []
|
|
279
302
|
http_thread = threading.Thread(
|
|
280
|
-
target=self._acquire_relukko,
|
|
303
|
+
target=self._acquire_relukko,
|
|
304
|
+
args=(url, max_run_time, payload, thread_store))
|
|
281
305
|
http_thread.start()
|
|
282
306
|
http_thread.join()
|
|
283
307
|
self.ws_listener.join()
|
|
@@ -1,24 +1,30 @@
|
|
|
1
|
+
# pylint: skip-file
|
|
2
|
+
"""
|
|
3
|
+
Testcontainers to be used in PyTests, for a fixture see tests/conftest.py
|
|
4
|
+
(relukko_backend):
|
|
5
|
+
|
|
6
|
+
@pytest.fixture(scope="session")
|
|
7
|
+
def relukko_backend():
|
|
8
|
+
with Network() as rl_net:
|
|
9
|
+
with RelukkoDbContainer(net=rl_net,
|
|
10
|
+
image="postgres:16", hostname="relukkodb") as _db:
|
|
11
|
+
db_url = "postgresql://relukko:relukko@relukkodb/relukko"
|
|
12
|
+
with RelukkoContainer(rl_net, db_url=db_url) as backend:
|
|
13
|
+
relukko = RelukkoClient(
|
|
14
|
+
base_url=backend.get_api_url(), api_key="somekey")
|
|
15
|
+
yield relukko, backend
|
|
16
|
+
"""
|
|
1
17
|
import socket
|
|
2
|
-
import ssl
|
|
3
|
-
import threading
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from typing import List
|
|
6
18
|
|
|
7
|
-
import pytest
|
|
8
19
|
from testcontainers.core.network import Network
|
|
9
20
|
from testcontainers.core.waiting_utils import wait_container_is_ready
|
|
10
21
|
from testcontainers.generic import ServerContainer
|
|
11
22
|
from testcontainers.postgres import PostgresContainer
|
|
12
23
|
|
|
13
|
-
from pyrelukko import RelukkoClient
|
|
14
|
-
|
|
15
|
-
SCRIPT_DIR = Path(__file__).parent.absolute()
|
|
16
|
-
INITDB_DIR = SCRIPT_DIR / "initdb.d"
|
|
17
|
-
|
|
18
24
|
|
|
19
25
|
class RelukkoContainer(ServerContainer):
|
|
20
26
|
def __init__(self, net: Network,
|
|
21
|
-
image="registry.gitlab.com/relukko/relukko:
|
|
27
|
+
image="registry.gitlab.com/relukko/relukko:latest", db_url=None):
|
|
22
28
|
self.db_url = db_url
|
|
23
29
|
self.net = net
|
|
24
30
|
super(RelukkoContainer, self).__init__(image=image, port=3000)
|
|
@@ -39,12 +45,19 @@ class RelukkoContainer(ServerContainer):
|
|
|
39
45
|
|
|
40
46
|
|
|
41
47
|
class RelukkoDbContainer(PostgresContainer):
|
|
42
|
-
def __init__(
|
|
48
|
+
def __init__(
|
|
49
|
+
self, net: Network,
|
|
50
|
+
image: str = "postgres:latest",
|
|
51
|
+
port: int = 5432,
|
|
52
|
+
username: str | None = None,
|
|
53
|
+
password: str | None = None,
|
|
54
|
+
dbname: str | None = None,
|
|
55
|
+
driver: str | None = "psycopg2",
|
|
56
|
+
**kwargs) -> None:
|
|
43
57
|
self.net = net
|
|
44
58
|
super().__init__(image, port, username, password, dbname, driver, **kwargs)
|
|
45
59
|
|
|
46
60
|
def _configure(self) -> None:
|
|
47
|
-
self.with_volume_mapping(INITDB_DIR, "/docker-entrypoint-initdb.d", "Z")
|
|
48
61
|
self.with_env("POSTGRES_USER", "relukko")
|
|
49
62
|
self.with_env("POSTGRES_PASSWORD", "relukko")
|
|
50
63
|
self.with_env("POSTGRES_DB", "relukko")
|
|
@@ -71,59 +84,3 @@ class RelukkoDbContainer(PostgresContainer):
|
|
|
71
84
|
buf = sock.recv(40)
|
|
72
85
|
if len(buf) == 0 and "SCRAM-SHA" not in buf:
|
|
73
86
|
raise ConnectionError
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
@pytest.fixture(scope="session")
|
|
77
|
-
def relukko_backend():
|
|
78
|
-
with Network() as rl_net:
|
|
79
|
-
with RelukkoDbContainer(net=rl_net,
|
|
80
|
-
image="postgres:16", hostname="relukkodb") as _db:
|
|
81
|
-
db_url = "postgresql://relukko:relukko@relukkodb/relukko"
|
|
82
|
-
with RelukkoContainer(rl_net, db_url=db_url) as backend:
|
|
83
|
-
relukko = RelukkoClient(
|
|
84
|
-
base_url=backend.get_api_url(), api_key="somekey")
|
|
85
|
-
yield relukko, backend
|
|
86
|
-
|
|
87
|
-
@pytest.fixture(scope="function")
|
|
88
|
-
def tls_listener():
|
|
89
|
-
|
|
90
|
-
certfile = SCRIPT_DIR / "cert" / "relukko.crt"
|
|
91
|
-
keyfile = SCRIPT_DIR / "cert" / "relukko.key"
|
|
92
|
-
|
|
93
|
-
def run_server(port_info: List, keep_running: threading.Event):
|
|
94
|
-
# Create a TCP socket
|
|
95
|
-
with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock:
|
|
96
|
-
sock.bind(("127.0.0.1", 0))
|
|
97
|
-
sock.listen(5) # Listen for incoming connections
|
|
98
|
-
|
|
99
|
-
_, assigned_port = sock.getsockname()
|
|
100
|
-
port_info.append(assigned_port)
|
|
101
|
-
|
|
102
|
-
# Wrap the socket with TLS
|
|
103
|
-
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
|
104
|
-
context.load_cert_chain(certfile=certfile, keyfile=keyfile)
|
|
105
|
-
with context.wrap_socket(sock, server_side=True) as ssock:
|
|
106
|
-
|
|
107
|
-
ssock.settimeout(1)
|
|
108
|
-
|
|
109
|
-
while keep_running.is_set():
|
|
110
|
-
try:
|
|
111
|
-
client_socket, _ = ssock.accept()
|
|
112
|
-
client_socket.sendall(b"Hello, TLS Client!")
|
|
113
|
-
client_socket.close()
|
|
114
|
-
except Exception as _:
|
|
115
|
-
continue
|
|
116
|
-
|
|
117
|
-
port_info = []
|
|
118
|
-
keep_running = threading.Event()
|
|
119
|
-
keep_running.set()
|
|
120
|
-
thread = threading.Thread(target=run_server, args=(port_info, keep_running))
|
|
121
|
-
thread.start()
|
|
122
|
-
|
|
123
|
-
while not port_info:
|
|
124
|
-
pass
|
|
125
|
-
|
|
126
|
-
yield thread, port_info[0]
|
|
127
|
-
|
|
128
|
-
keep_running.clear()
|
|
129
|
-
thread.join()
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# pylint: disable=all
|
|
2
|
-
__version__ = "0.
|
|
2
|
+
__version__ = "0.4.0"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# How To
|
|
2
|
+
```
|
|
3
|
+
openssl req -subj '/CN=Relukko CA' -x509 -sha256 -days 7300 -noenc -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt -addext keyUsage=critical,cRLSign,digitalSignature,keyCertSign
|
|
4
|
+
|
|
5
|
+
ln -s rootCA.crt "$(openssl x509 -hash -noout -in rootCA.crt).0"
|
|
6
|
+
|
|
7
|
+
openssl req -subj '/CN=relukko' -newkey rsa:2048 -noenc -keyout relukko.key -out relukko.csr -addext keyUsage=critical,digitalSignature,keyEncipherment,keyAgreement -addext extendedKeyUsage=critical,serverAuth
|
|
8
|
+
|
|
9
|
+
openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in relukko.csr -out relukko.crt -days 7299 -CAcreateserial
|
|
10
|
+
openssl x509 -inform PEM -in rootCA.crt -outform DER -out rootCA.der
|
|
11
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIC9zCCAd+gAwIBAgIUXFQN+AOO7KFdiVNVFman8BLkRfkwDQYJKoZIhvcNAQEL
|
|
3
|
+
BQAwFTETMBEGA1UEAwwKUmVsdWtrbyBDQTAeFw0yNDExMTYyMTM5MTNaFw00NDEx
|
|
4
|
+
MTAyMTM5MTNaMBIxEDAOBgNVBAMMB3JlbHVra28wggEiMA0GCSqGSIb3DQEBAQUA
|
|
5
|
+
A4IBDwAwggEKAoIBAQCljry3blOWFJRdinzcH4XzRnvKlhhofBhtRsPH+pvjmrHO
|
|
6
|
+
v52rXj1XeHqXaEBevhNiN7lP5eg2UgOrs0KAVXYR2Na9Mxrh8ACX+IqeEJF9BKgO
|
|
7
|
+
4t2RvItDU3SWxV3dIYMasBhe/iDXDKKZd/jVOiluL9zuxo9ltDagZxc72jWMnvrO
|
|
8
|
+
lvlnZVEtH4n9i+hnx1daWRZG87DjO6d8I8F8nX6NTqJgBlrRm8jlcq2N/G8eHTFq
|
|
9
|
+
OrLY4xk4CF+aVExpJrEGprfhNkbE025tJIbGNM9Xv+W0sI/nhEwJdv4ifEP/b+44
|
|
10
|
+
n+KHrAurOboFYmRcoZ9Vn4C1KuYBvDOpgkwOs1wtAgMBAAGjQjBAMB0GA1UdDgQW
|
|
11
|
+
BBSy6DZz/N1PW1mkQY7HUj3Fz6yZOjAfBgNVHSMEGDAWgBT+sHazfmyczKb0BV6r
|
|
12
|
+
Z1JQ8Sfx9zANBgkqhkiG9w0BAQsFAAOCAQEAL1c1l3Azna1mh86haErurYk3EsiH
|
|
13
|
+
KDGprRubdB5qfpa2GdAkhitp9juKYdKGdw877eOl5z7AMeMWAA8WXQ3z7jkQkUhU
|
|
14
|
+
9wsZxNyHQajq6Lo9KsRxZiRKZX/fxagcnDem+4xTvzSlJoAT5p/CO5E31odwWkZN
|
|
15
|
+
bg79I36nk87opISXzNAbMBcbQEV5R8l4PzNGs/DcrLzTC66FKxHHzyih4mlBF5mS
|
|
16
|
+
/sMY5l9QNaJHKPK7fKZ5yxohkda7tDwtb5p0bbEUQlMeZIQ8r/go1b7/ppXXM5ei
|
|
17
|
+
mTDcwKgeOBgVujqhvgGXOKtcHVfkrqcID+qgDMxYd7XXE/icGF3zmnHwDQ==
|
|
18
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE REQUEST-----
|
|
2
|
+
MIICkDCCAXgCAQAwEjEQMA4GA1UEAwwHcmVsdWtrbzCCASIwDQYJKoZIhvcNAQEB
|
|
3
|
+
BQADggEPADCCAQoCggEBAKWOvLduU5YUlF2KfNwfhfNGe8qWGGh8GG1Gw8f6m+Oa
|
|
4
|
+
sc6/natePVd4epdoQF6+E2I3uU/l6DZSA6uzQoBVdhHY1r0zGuHwAJf4ip4QkX0E
|
|
5
|
+
qA7i3ZG8i0NTdJbFXd0hgxqwGF7+INcMopl3+NU6KW4v3O7Gj2W0NqBnFzvaNYye
|
|
6
|
+
+s6W+WdlUS0fif2L6GfHV1pZFkbzsOM7p3wjwXydfo1OomAGWtGbyOVyrY38bx4d
|
|
7
|
+
MWo6stjjGTgIX5pUTGkmsQamt+E2RsTTbm0khsY0z1e/5bSwj+eETAl2/iJ8Q/9v
|
|
8
|
+
7jif4oesC6s5ugViZFyhn1WfgLUq5gG8M6mCTA6zXC0CAwEAAaA5MDcGCSqGSIb3
|
|
9
|
+
DQEJDjEqMCgwDgYDVR0PAQH/BAQDAgOoMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMB
|
|
10
|
+
MA0GCSqGSIb3DQEBCwUAA4IBAQBfEyjmGQtITqSsmoAQXEb11Cm/olsL5w6kEzgr
|
|
11
|
+
/0K8ASvDvW+3yJ3U9OBngvgh6iQCJjYaixb8NtQS7yVWYEqJoaA0Hp1q0QDmRS/l
|
|
12
|
+
MDLe2cILgbLQUKOf1jLtYsLG93Lb74HSGztjIIEoi3Wgrm5LLGc/cd28q8yw5c/j
|
|
13
|
+
s1EntUHeNWCYAUIRvwmt+1UPcc8EBHH2DugGz2verzARdvLWAajL5r9ZIJkkU0kY
|
|
14
|
+
fh5gnmVb6I6RtIXhWcXMUL9nBwzPCyJMd4cC/fueC+HxzLNhGldvVxj3cg7W57vR
|
|
15
|
+
QnbG/qcJYN5WGhoHrWIiI90GufG4jifVvyQeBC/vQcymRlAL
|
|
16
|
+
-----END CERTIFICATE REQUEST-----
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-----BEGIN PRIVATE KEY-----
|
|
2
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCljry3blOWFJRd
|
|
3
|
+
inzcH4XzRnvKlhhofBhtRsPH+pvjmrHOv52rXj1XeHqXaEBevhNiN7lP5eg2UgOr
|
|
4
|
+
s0KAVXYR2Na9Mxrh8ACX+IqeEJF9BKgO4t2RvItDU3SWxV3dIYMasBhe/iDXDKKZ
|
|
5
|
+
d/jVOiluL9zuxo9ltDagZxc72jWMnvrOlvlnZVEtH4n9i+hnx1daWRZG87DjO6d8
|
|
6
|
+
I8F8nX6NTqJgBlrRm8jlcq2N/G8eHTFqOrLY4xk4CF+aVExpJrEGprfhNkbE025t
|
|
7
|
+
JIbGNM9Xv+W0sI/nhEwJdv4ifEP/b+44n+KHrAurOboFYmRcoZ9Vn4C1KuYBvDOp
|
|
8
|
+
gkwOs1wtAgMBAAECggEAAlGzzikAoqYfc7wywBDXLkXjClhpN2t6zYStTbhlvyQ4
|
|
9
|
+
9rgdJA9CC9JI+1gVqlrkyB5j0IOPg27i+y1PBblMwF0mf7t+/KiOEl+3R2J2VODZ
|
|
10
|
+
q6Dp110KB8bCdLGg/TqqZld02/D/S98ZY83eezqUZbH/cqVu6rVbaSQdWyeh7Bow
|
|
11
|
+
0rfnMV2537JpZVXzmVDGhlhKcgKjJFkzdW4Zv34lMSOCAAeByrIJtPEoQrJ7MQOj
|
|
12
|
+
9WpwYN+JN4YeP1FWXIG3Ah7ivFsCMZN9MEvXWMcEnAqSHhXXyRzJnJh4jBrigfM1
|
|
13
|
+
JeqDWgiMlCLP5Z2CwA8ahTnJZAYBJUfeFiNHBYC1sQKBgQDjoTCIlCr7UyLkxaJr
|
|
14
|
+
+IY65tl0jjWiEEvSZ9E+fqqesAsABGE8Po1ZEA7VZNViFf+4ttuBZLngmm/YVBvV
|
|
15
|
+
Ok+hf1HSDsvNhon7oIIa7cxlYGKH2Lf6tq8ovtt7IXRknInbbxh6+CoMm5Yc1KXp
|
|
16
|
+
XRCApfeBEoQdM2N2TRLUL+pPkQKBgQC6MQ9L3zMEr2yXrkyi2wmqBMMaSHCM5Zuh
|
|
17
|
+
ifQSFjJfkarh2y0KN7I73HR6KJVMVRVSmARi/QgN8tEvaXjCvVN67re4mDiZ5rC+
|
|
18
|
+
uIx903tkuKR4ruC1DE96NtsM1VNh1mUa2ndPULztpqPXhMCPspMltH4KbJHLo/iv
|
|
19
|
+
MaRHu2Ps3QKBgDGluIYxeuZyDYxEJtbRz8UNEKTBV6VPVJpBlnvA+Mm/r8aDLgoL
|
|
20
|
+
wpyIShP0+C16itno2Btysq/wPzC5t5BcNX4N3PSp0X20OGgva/EfqJL74MGsXQRL
|
|
21
|
+
0AxdBFXoyBAhrFe19WrssY8qaCVFpCIv8Cd/C2qVdUdBLBJjYRXylXJhAoGBAIPX
|
|
22
|
+
z5QTReYwbj3uD5hWcD5zRtBqsUAkKpM1w523GA5ycMWj1P3iOJSI4/XInQfDS+kD
|
|
23
|
+
ej+6GyT9Z0Eid3+2XtGzDmdpatMX9tnmhp1mzn6g/N30P2wUfob1JyGsQXILRebB
|
|
24
|
+
AjEo48+I64XmHBDlC6tsZr/s50SDJMqx5TliKT0FAoGAeqqC57jD2bj8Srs1Xa9p
|
|
25
|
+
JDZdS1DU/HthIngHTlud/rvOs2koVbIKRAHqxoBn2TCii6srFf7nHgLZ4iDOiyHF
|
|
26
|
+
eOb52GaYYKQNiSF77LUV0wdxmwwhm3h6hRYgt52nT1JVHH6rilZ64e2mevPX5H1T
|
|
27
|
+
CVvlmUZTRqXOidoSGMkO3sQ=
|
|
28
|
+
-----END PRIVATE KEY-----
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDGzCCAgOgAwIBAgIURXOBbBP+BSnq15fqso3+0Wkwt2swDQYJKoZIhvcNAQEL
|
|
3
|
+
BQAwFTETMBEGA1UEAwwKUmVsdWtrbyBDQTAeFw0yNDExMTYyMTM4MDVaFw00NDEx
|
|
4
|
+
MTEyMTM4MDVaMBUxEzARBgNVBAMMClJlbHVra28gQ0EwggEiMA0GCSqGSIb3DQEB
|
|
5
|
+
AQUAA4IBDwAwggEKAoIBAQDSDxl9hWmwLjTwJTHTH55HwNFKDMHXjiMmig2SMVCE
|
|
6
|
+
Y9fRYNms46CU+ulGGr8TMqXExb3J1ywE/HB8PBYoPKvAmPBHrquXT03A64fXl30q
|
|
7
|
+
IcnRHsJymxmUQV7yQxyfIXHT57NGUBauRhYSG8enbTNPbwByAdDAK6z0/41mMPbz
|
|
8
|
+
NFSXR89+ZkYf0CfKkvi/lPGdC80rS9LokLvDniVT50ir4CurhzndBP/U82nTMxvr
|
|
9
|
+
+Q2/TQmxbzeHOpa4ZCD2OBAHNXAGgV1qltnhvmbn+zYEK+vt9ZSb6lRUXWBWUvkn
|
|
10
|
+
TRCy3lMHu27q5h8Gzzxvi0Ct2lJ02poZG98QlXoAto+RAgMBAAGjYzBhMB0GA1Ud
|
|
11
|
+
DgQWBBT+sHazfmyczKb0BV6rZ1JQ8Sfx9zAfBgNVHSMEGDAWgBT+sHazfmyczKb0
|
|
12
|
+
BV6rZ1JQ8Sfx9zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkq
|
|
13
|
+
hkiG9w0BAQsFAAOCAQEAASuRdyC8zk+FD3DO8vO3bpxiewqjSjQ0cE/t2XU3floV
|
|
14
|
+
r6Lp1bS+IjpeKIYzTg3+DdIMGub8piCh7JcU5ru1Ef0/xwtmCCUB/rOcYwfa2nHj
|
|
15
|
+
w7sc+njSnmdpISCyUV9Yxsqs+b2eQOMj/D28R5c2vf7QIYQMJivqa44TrMy57mJP
|
|
16
|
+
Tu+Y4stHZnfrnlggScfjn+dKjT58awyI0UVPr80YWZuSIDx26CREP41X8SJ5qRMN
|
|
17
|
+
K6KFXxN/PJhl/Y5axV/k/omRXd1FusUaC8yGk5E4zCs7cvbhG830FVIM19zbVSKg
|
|
18
|
+
SF6Dvx3mEWraHyBls9e+FYQIxB5FEJz9KGZdsOSjcQ==
|
|
19
|
+
-----END CERTIFICATE-----
|
|
Binary file
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-----BEGIN PRIVATE KEY-----
|
|
2
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDSDxl9hWmwLjTw
|
|
3
|
+
JTHTH55HwNFKDMHXjiMmig2SMVCEY9fRYNms46CU+ulGGr8TMqXExb3J1ywE/HB8
|
|
4
|
+
PBYoPKvAmPBHrquXT03A64fXl30qIcnRHsJymxmUQV7yQxyfIXHT57NGUBauRhYS
|
|
5
|
+
G8enbTNPbwByAdDAK6z0/41mMPbzNFSXR89+ZkYf0CfKkvi/lPGdC80rS9LokLvD
|
|
6
|
+
niVT50ir4CurhzndBP/U82nTMxvr+Q2/TQmxbzeHOpa4ZCD2OBAHNXAGgV1qltnh
|
|
7
|
+
vmbn+zYEK+vt9ZSb6lRUXWBWUvknTRCy3lMHu27q5h8Gzzxvi0Ct2lJ02poZG98Q
|
|
8
|
+
lXoAto+RAgMBAAECggEAMnh7TOv5xWGMyah+LLZ7nszm3G5tQr/9lRx1f0tHB9A/
|
|
9
|
+
gijNlFtK8ZDJ7NSvVUsFhl5mp/EBvB71XfxH7JoLQGbe0LJYuy3MRk6xIG1fHvjo
|
|
10
|
+
V00XNlcq0bLVP8s9PMTZ5yrUKdBDatMfKXGwSnuT6QGIL1xdTlcQIvul+0hHhY58
|
|
11
|
+
+QGhB1HJASChg13OjLFwDhjiUqH1rkr8WjFspZZIm+SrwXUZTr6PYkF4E1cBcsWT
|
|
12
|
+
4PLCYKTZTKKr3D0UVa5ipOkp/ZIgWqRk1SACn84G1/AkmBpgv+0XgZz8kZ0Ju+9W
|
|
13
|
+
sPQV/fxXYpvnM/cvkHBAnvWDp4N3VX648zez7t+f2wKBgQD7guX7G5LdtLB/Crlx
|
|
14
|
+
uyAhkJyvc8Ttt11HCf2T/k6oqhATt9014NlJYQY2pVlyoyEQEb1Pe919ei+UpVVt
|
|
15
|
+
Ahaanw5xveOeGdjc2YJIqQV4mqc/daEXFfyLU+3dCzTKB4AXaIT09If5mna46Ou/
|
|
16
|
+
q1UW96cH/SqLC5Z3CyUhqwIvfwKBgQDVztB2P1KBH45lOT1oP/vPxYklUSokA/g+
|
|
17
|
+
VRw3pB8Wmm86fSxQ1lEvMViVf/tyrc+dpvNS+7quNzc0U/2+vpMcLjBkS9EpxAMy
|
|
18
|
+
hPDwZPnPXHKHnC/ET9WWO+wVaCTienGSVaTDTToeKo71Oesi1etHkLl0aWEMp8vo
|
|
19
|
+
gYGPM+/I7wKBgF0dNhXEPJhWF+3Aw60mcRvcFRYjzymO9DqjqTzMLsTkyTTzojMb
|
|
20
|
+
PnabNBixGK+HU2tGlgbCPdsBjHIEz96eok22Szuy6H0U5qPE5yYNZVgkMX0eCHiq
|
|
21
|
+
jCfs96gZSP7uze5cpLSnf1vaYs/Mc9MvFD5/i1g60zBNJvSFrMaNMC7zAoGBANNp
|
|
22
|
+
y+GQ3aEGNgRLZDgIRJN/DQyURCoWrsnb2KoAJClyjZd1HHPWZ7JVhfVV9qm/yjJm
|
|
23
|
+
WeXtOft4Z6LbhmWtBcPwvDMAcRNuWYcDw0bBYe6zyB/lxanFEzqZh+jm8MntLw32
|
|
24
|
+
l5PycgxQIsnC+omYoyxBo8/DP46HAO6n2Bdk0K6LAoGACP/UfrAg4Hyqi0jJcusl
|
|
25
|
+
Led0R3Fl0dw5i2N9PB++PUajt5LFhXXGHeOQnTlYbeJ/ioJgRS/k6W7MH43zP0me
|
|
26
|
+
wIYrVmazCewXwcIZiRv3ees73OsAVrn/yl17+u4KkVlXi0me8Opljl4/MS8026rE
|
|
27
|
+
iKMsJnco7XH/vaS9MrrrOvE=
|
|
28
|
+
-----END PRIVATE KEY-----
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
5C540DF8038EECA15D8953551666A7F012E445F9
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import socket
|
|
3
|
+
import ssl
|
|
4
|
+
import threading
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import List
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
from testcontainers.core.network import Network
|
|
10
|
+
|
|
11
|
+
from pyrelukko import RelukkoClient
|
|
12
|
+
from pyrelukko.testcontainers import RelukkoContainer, RelukkoDbContainer
|
|
13
|
+
|
|
14
|
+
SCRIPT_DIR = Path(__file__).parent.absolute()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.fixture(scope="session")
|
|
18
|
+
def relukko_backend():
|
|
19
|
+
if os.environ.get("CI_HAS_RELUKKO"):
|
|
20
|
+
# Gitlab does not allow DinD networks, so Relukko runs as a service
|
|
21
|
+
# in the background of the job.
|
|
22
|
+
relukko = RelukkoClient(
|
|
23
|
+
base_url=os.environ['CI_RELUKKO_BASE_URL'],
|
|
24
|
+
api_key=os.environ['CI_RELUKKO_API_KEY']
|
|
25
|
+
)
|
|
26
|
+
yield relukko, None
|
|
27
|
+
else:
|
|
28
|
+
with Network() as rl_net:
|
|
29
|
+
with RelukkoDbContainer(net=rl_net,
|
|
30
|
+
image="postgres:16", hostname="relukkodb") as _db:
|
|
31
|
+
db_url = "postgresql://relukko:relukko@relukkodb/relukko"
|
|
32
|
+
with RelukkoContainer(rl_net, db_url=db_url) as backend:
|
|
33
|
+
relukko = RelukkoClient(
|
|
34
|
+
base_url=backend.get_api_url(), api_key="somekey")
|
|
35
|
+
yield relukko, backend
|
|
36
|
+
|
|
37
|
+
@pytest.fixture(scope="function")
|
|
38
|
+
def tls_listener():
|
|
39
|
+
|
|
40
|
+
certfile = SCRIPT_DIR / "cert" / "relukko.crt"
|
|
41
|
+
keyfile = SCRIPT_DIR / "cert" / "relukko.key"
|
|
42
|
+
|
|
43
|
+
def run_server(port_info: List, keep_running: threading.Event):
|
|
44
|
+
# Create a TCP socket
|
|
45
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock:
|
|
46
|
+
sock.bind(("127.0.0.1", 0))
|
|
47
|
+
sock.listen(5) # Listen for incoming connections
|
|
48
|
+
|
|
49
|
+
_, assigned_port = sock.getsockname()
|
|
50
|
+
port_info.append(assigned_port)
|
|
51
|
+
|
|
52
|
+
# Wrap the socket with TLS
|
|
53
|
+
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
|
54
|
+
context.load_cert_chain(certfile=certfile, keyfile=keyfile)
|
|
55
|
+
with context.wrap_socket(sock, server_side=True) as ssock:
|
|
56
|
+
|
|
57
|
+
ssock.settimeout(1)
|
|
58
|
+
|
|
59
|
+
while keep_running.is_set():
|
|
60
|
+
try:
|
|
61
|
+
client_socket, _ = ssock.accept()
|
|
62
|
+
client_socket.sendall(b"Hello, TLS Client!")
|
|
63
|
+
client_socket.close()
|
|
64
|
+
except Exception as _:
|
|
65
|
+
continue
|
|
66
|
+
|
|
67
|
+
port_info = []
|
|
68
|
+
keep_running = threading.Event()
|
|
69
|
+
keep_running.set()
|
|
70
|
+
thread = threading.Thread(target=run_server, args=(port_info, keep_running))
|
|
71
|
+
thread.start()
|
|
72
|
+
|
|
73
|
+
while not port_info:
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
yield thread, port_info[0]
|
|
77
|
+
|
|
78
|
+
keep_running.clear()
|
|
79
|
+
thread.join()
|
|
@@ -2,7 +2,7 @@ import logging
|
|
|
2
2
|
import time
|
|
3
3
|
import ssl
|
|
4
4
|
import socket
|
|
5
|
-
from datetime import datetime, timezone
|
|
5
|
+
from datetime import datetime, timedelta, timezone
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Dict
|
|
8
8
|
|
|
@@ -32,7 +32,7 @@ def _check_tls(ssl_ctx: ssl.SSLContext, port):
|
|
|
32
32
|
|
|
33
33
|
def _check_has_serial_no(ssl_ctx: ssl.SSLContext):
|
|
34
34
|
serial_numbers = [x["serialNumber"] for x in ssl_ctx.get_ca_certs()]
|
|
35
|
-
assert "
|
|
35
|
+
assert "4573816C13FE0529EAD797EAB28DFED16930B76B" in serial_numbers
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
def test_init_relukko_client():
|
|
@@ -59,6 +59,11 @@ def test_init_relukko_client():
|
|
|
59
59
|
assert relukko.backoff == 2.0
|
|
60
60
|
assert relukko.max_delay is None
|
|
61
61
|
assert relukko.exceptions == (requests.ConnectionError, RelukkoDoRetry)
|
|
62
|
+
assert relukko.ws_wait_for_timeout == 2
|
|
63
|
+
assert relukko.ws_ping_interval == 60
|
|
64
|
+
assert relukko.ws_ping_timeout == 20
|
|
65
|
+
assert relukko.acquire_wait_for_timeout == 2
|
|
66
|
+
assert relukko.acquire_modulo == 100
|
|
62
67
|
|
|
63
68
|
with pytest.raises(ValueError):
|
|
64
69
|
RelukkoClient(base_url=1000, api_key="")
|
|
@@ -152,7 +157,7 @@ def test_reconfigure_relukko_client():
|
|
|
152
157
|
"https://relukko", api_key="secret-key")
|
|
153
158
|
|
|
154
159
|
assert relukko.base_url == parse_url("https://relukko")
|
|
155
|
-
assert relukko.ws_url == parse_url("wss://relukko/
|
|
160
|
+
assert relukko.ws_url == parse_url("wss://relukko/ws/broadcast")
|
|
156
161
|
assert relukko.session.headers['X-api-Key'] == "secret-key"
|
|
157
162
|
|
|
158
163
|
default_ctx = ssl.create_default_context()
|
|
@@ -169,6 +174,11 @@ def test_reconfigure_relukko_client():
|
|
|
169
174
|
assert relukko.backoff == 2.0
|
|
170
175
|
assert relukko.max_delay is None
|
|
171
176
|
assert relukko.exceptions == (requests.ConnectionError, RelukkoDoRetry)
|
|
177
|
+
assert relukko.ws_wait_for_timeout == 2
|
|
178
|
+
assert relukko.ws_ping_interval == 60
|
|
179
|
+
assert relukko.ws_ping_timeout == 20
|
|
180
|
+
assert relukko.acquire_wait_for_timeout == 2
|
|
181
|
+
assert relukko.acquire_modulo == 100
|
|
172
182
|
|
|
173
183
|
|
|
174
184
|
def test_reconfigure_relukko_client_extended():
|
|
@@ -178,6 +188,11 @@ def test_reconfigure_relukko_client_extended():
|
|
|
178
188
|
verify_mode = ssl.VerifyMode.CERT_NONE
|
|
179
189
|
verify_flags = ssl.VerifyFlags.VERIFY_DEFAULT
|
|
180
190
|
options = ssl.Options.OP_ALL
|
|
191
|
+
ws_wait_for_timeout = 27
|
|
192
|
+
ws_ping_interval = 600
|
|
193
|
+
ws_ping_timeout = 23
|
|
194
|
+
acquire_wait_for_timeout = 22
|
|
195
|
+
acquire_modulo = 202
|
|
181
196
|
|
|
182
197
|
relukko.reconfigure_relukko(
|
|
183
198
|
base_url="https://relukko", api_key="my-API-key", trust_env=False,
|
|
@@ -185,13 +200,16 @@ def test_reconfigure_relukko_client_extended():
|
|
|
185
200
|
status=96, other=95, backoff_factor=94, backoff_max=1000,
|
|
186
201
|
backoff_jitter=93, raise_on_redirect=False, raise_on_status=False,
|
|
187
202
|
check_hostname=False, hostname_checks_common_name=False,
|
|
188
|
-
verify_mode=verify_mode, verify_flags=verify_flags, options=options
|
|
203
|
+
verify_mode=verify_mode, verify_flags=verify_flags, options=options,
|
|
204
|
+
ws_wait_for_timeout=ws_wait_for_timeout, acquire_modulo=acquire_modulo,
|
|
205
|
+
ws_ping_interval=ws_ping_interval, ws_ping_timeout=ws_ping_timeout,
|
|
206
|
+
acquire_wait_for_timeout=acquire_wait_for_timeout,
|
|
189
207
|
)
|
|
190
208
|
|
|
191
209
|
assert relukko.session.trust_env == False
|
|
192
210
|
assert relukko.session.cookies == cookies
|
|
193
211
|
assert relukko.base_url == parse_url("https://relukko")
|
|
194
|
-
assert relukko.ws_url == parse_url("wss://relukko/
|
|
212
|
+
assert relukko.ws_url == parse_url("wss://relukko/ws/broadcast")
|
|
195
213
|
assert relukko.session.headers['X-api-Key'] == "my-API-key"
|
|
196
214
|
http_adapter: HTTPAdapter = relukko.session.adapters.get("http://")
|
|
197
215
|
assert http_adapter.max_retries.total == 100
|
|
@@ -218,22 +236,35 @@ def test_reconfigure_relukko_client_extended():
|
|
|
218
236
|
assert relukko.backoff == 2.0
|
|
219
237
|
assert relukko.max_delay is None
|
|
220
238
|
assert relukko.exceptions == (requests.ConnectionError, RelukkoDoRetry)
|
|
239
|
+
assert relukko.ws_wait_for_timeout == ws_wait_for_timeout
|
|
240
|
+
assert relukko.ws_ping_interval == ws_ping_interval
|
|
241
|
+
assert relukko.ws_ping_timeout == ws_ping_timeout
|
|
242
|
+
assert relukko.acquire_wait_for_timeout == acquire_wait_for_timeout
|
|
243
|
+
assert relukko.acquire_modulo == acquire_modulo
|
|
221
244
|
|
|
222
245
|
|
|
223
246
|
def test_init_relukko_client_extented():
|
|
224
247
|
cookies = cookiejar_from_dict({"cookie1": "value1"})
|
|
248
|
+
ws_wait_for_timeout = 27
|
|
249
|
+
ws_ping_interval = 600
|
|
250
|
+
ws_ping_timeout = 23
|
|
251
|
+
acquire_wait_for_timeout = 22
|
|
252
|
+
acquire_modulo = 202
|
|
225
253
|
|
|
226
254
|
relukko = RelukkoClient(
|
|
227
255
|
base_url="http://relukko", api_key="my-API-key", trust_env=False,
|
|
228
256
|
cookies=cookies, total=100, connect=99, read=98, redirect=97,
|
|
229
257
|
status=96, other=95, backoff_factor=94, backoff_max=1000,
|
|
230
258
|
backoff_jitter=93, raise_on_redirect=False, raise_on_status=False,
|
|
259
|
+
ws_wait_for_timeout=ws_wait_for_timeout, acquire_modulo=acquire_modulo,
|
|
260
|
+
ws_ping_interval=ws_ping_interval, ws_ping_timeout=ws_ping_timeout,
|
|
261
|
+
acquire_wait_for_timeout=acquire_wait_for_timeout,
|
|
231
262
|
)
|
|
232
263
|
|
|
233
264
|
assert relukko.session.trust_env == False
|
|
234
265
|
assert relukko.session.cookies == cookies
|
|
235
266
|
assert relukko.base_url == parse_url("http://relukko")
|
|
236
|
-
assert relukko.ws_url == parse_url("ws://relukko/
|
|
267
|
+
assert relukko.ws_url == parse_url("ws://relukko/ws/broadcast")
|
|
237
268
|
assert relukko.session.headers['X-api-Key'] == "my-API-key"
|
|
238
269
|
assert relukko.ssl_ctx is None
|
|
239
270
|
http_adapter: HTTPAdapter = relukko.session.adapters.get("http://")
|
|
@@ -253,6 +284,11 @@ def test_init_relukko_client_extented():
|
|
|
253
284
|
assert relukko.backoff == 2.0
|
|
254
285
|
assert relukko.max_delay is None
|
|
255
286
|
assert relukko.exceptions == (requests.ConnectionError, RelukkoDoRetry)
|
|
287
|
+
assert relukko.ws_wait_for_timeout == ws_wait_for_timeout
|
|
288
|
+
assert relukko.ws_ping_interval == ws_ping_interval
|
|
289
|
+
assert relukko.ws_ping_timeout == ws_ping_timeout
|
|
290
|
+
assert relukko.acquire_wait_for_timeout == acquire_wait_for_timeout
|
|
291
|
+
assert relukko.acquire_modulo == acquire_modulo
|
|
256
292
|
|
|
257
293
|
|
|
258
294
|
def test_init_relukko_client_ssl_ctx():
|
|
@@ -351,7 +387,25 @@ def test_acquire_relukko(relukko_backend):
|
|
|
351
387
|
lock = relukko.acquire_relukko("pylock", "pytest", 30)
|
|
352
388
|
end_time = time.time()
|
|
353
389
|
assert lock is None
|
|
354
|
-
assert 29 < end_time - start_time <
|
|
390
|
+
assert 29 < end_time - start_time < 45
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def test_acquire_relukko_with_del(relukko_backend):
|
|
394
|
+
relukko, _ = relukko_backend
|
|
395
|
+
lock = relukko.acquire_relukko("Pylock", "pytest", 10)
|
|
396
|
+
id = lock['id']
|
|
397
|
+
|
|
398
|
+
expires_at = datetime.now(timezone.utc) - timedelta(minutes=2, seconds=45)
|
|
399
|
+
upd_lock = relukko.update_relukko(id, expires_at=expires_at)
|
|
400
|
+
assert id == upd_lock['id']
|
|
401
|
+
|
|
402
|
+
start_time = time.time()
|
|
403
|
+
lock = relukko.acquire_relukko("Pylock", "pytest", 90)
|
|
404
|
+
end_time = time.time()
|
|
405
|
+
|
|
406
|
+
assert lock is not None
|
|
407
|
+
assert upd_lock['id'] != lock['id']
|
|
408
|
+
assert 29 < end_time - start_time < 50
|
|
355
409
|
|
|
356
410
|
|
|
357
411
|
def test_delete_relukko(relukko_backend):
|
pyrelukko-0.2.0/.pylintrc.toml
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
[tool.pylint.main]
|
|
2
|
-
# Files or directories to be skipped. They should be base names, not paths.
|
|
3
|
-
ignore = ["LICENSE", "pyproject.toml", "version.py",
|
|
4
|
-
"README.md", "demo.py", "conftest.py"]
|
|
5
|
-
|
|
6
|
-
# Files or directories matching the regular expression patterns are skipped. The
|
|
7
|
-
# regex matches against base names, not paths. The default value ignores Emacs
|
|
8
|
-
# file locks
|
|
9
|
-
ignore-patterns = ["^\\.#", "^test_"]
|
pyrelukko-0.2.0/pyproject.toml
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
[project]
|
|
2
|
-
name = "pyrelukko"
|
|
3
|
-
authors = [
|
|
4
|
-
{name = "Reto Zingg", email = "g.d0b3rm4n@gmail.com"},
|
|
5
|
-
]
|
|
6
|
-
readme = "README.md"
|
|
7
|
-
|
|
8
|
-
# https://pypi.org/pypi?%3Aaction=list_classifiers
|
|
9
|
-
classifiers = [
|
|
10
|
-
"Development Status :: 3 - Alpha",
|
|
11
|
-
"Intended Audience :: Developers",
|
|
12
|
-
"License :: OSI Approved :: MIT License",
|
|
13
|
-
"Topic :: Internet :: WWW/HTTP",
|
|
14
|
-
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
15
|
-
]
|
|
16
|
-
requires-python = ">=3.12"
|
|
17
|
-
dynamic = ["version", "description"]
|
|
18
|
-
dependencies = [
|
|
19
|
-
"requests >=2.32.3",
|
|
20
|
-
]
|
|
21
|
-
|
|
22
|
-
[tool.flit.sdist]
|
|
23
|
-
exclude = [".gitignore", "demo.py"]
|
|
24
|
-
|
|
25
|
-
[project.urls]
|
|
26
|
-
Homepage = "https://gitlab.com/relukko/pyrelukko"
|
|
27
|
-
Issues = "https://gitlab.com/relukko/pyrelukko/-/issues"
|
|
28
|
-
|
|
29
|
-
[build-system]
|
|
30
|
-
requires = ["flit_core >=3.2,<4", "semantic-version >= 2.10"]
|
|
31
|
-
build-backend = "flit_core.buildapi"
|
|
32
|
-
|
|
33
|
-
[tool.pytest.ini_options]
|
|
34
|
-
testpaths = [
|
|
35
|
-
"tests",
|
|
36
|
-
]
|
|
37
|
-
pythonpath = [
|
|
38
|
-
"src",
|
|
39
|
-
]
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# How To
|
|
2
|
-
```
|
|
3
|
-
openssl req -x509 -sha256 -days 7300 -noenc -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
|
|
4
|
-
ln -s rootCA.crt "$(openssl x509 -hash -noout -in rootCA.crt)"
|
|
5
|
-
openssl req -newkey rsa:2048 -noenc -keyout relukko.key -out relukko.csr
|
|
6
|
-
openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in relukko.csr -out relukko.crt -days 7299 -CAcreateserial
|
|
7
|
-
openssl x509 -inform PEM -in rootCA.crt -outform DER -out rootCA.der
|
|
8
|
-
```
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
-----BEGIN CERTIFICATE-----
|
|
2
|
-
MIIDeDCCAmCgAwIBAgIUIG2mO1IxfM3wqiLLFCO+6ubGdHswDQYJKoZIhvcNAQEL
|
|
3
|
-
BQAwVDELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UE
|
|
4
|
-
CgwTRGVmYXVsdCBDb21wYW55IEx0ZDEQMA4GA1UEAwwHUmVsdWtrbzAeFw0yNDEx
|
|
5
|
-
MTMxNTQxNTdaFw00NDExMDcxNTQxNTdaMFQxCzAJBgNVBAYTAlhYMRUwEwYDVQQH
|
|
6
|
-
DAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQxEDAO
|
|
7
|
-
BgNVBAMMB3JlbHVra28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCr
|
|
8
|
-
89++zNQs+MG5opoCTWq/QxAJsr9Uul598XoQFXn1N/d/JOeSosy8BNvb1RXsr5sp
|
|
9
|
-
sNJbJEun6OPFtUoVczUtivS99XNchWPjEQ18w22aiLcwl/uOrdfxWj04yEfKmejN
|
|
10
|
-
ZXFrShhAWRGfc3fi2hD0Y5mtbS7T5iqaYzm4U5UDVFizVPnSgPFXMAiat/VQGvBF
|
|
11
|
-
cv5IpBjXOJGkLZTzmFlW61T6m+MJGXF59CLC6vL6QJCqQpSUWG9UM00R8L2pQ1b8
|
|
12
|
-
HLKYUuJ+vp4WVYwYyz769BNG4OG3IkdqIHKDFWBXFVmKaUkX9aAul4BOitKy4XFc
|
|
13
|
-
8eu653lbkVnRHb01RaP7AgMBAAGjQjBAMB0GA1UdDgQWBBSEFybZBM4O7khSofZl
|
|
14
|
-
0oAT+CSXEjAfBgNVHSMEGDAWgBRAo64Da82emF0q53wCdj4wbFTmMDANBgkqhkiG
|
|
15
|
-
9w0BAQsFAAOCAQEAs+zaKt8VqLoVT0OT24Oxyzc+/A0h4BYq3kYD11BaUJ6oKqQu
|
|
16
|
-
57FRKi0ZWxNSNCbzrwi6W+qNgIXtvSHWk4+BKxzqDVG6LCIuNn4bbvlQMGuTWctY
|
|
17
|
-
ndArPxdKvN9AXeCvam+5XKcA5OJY/naoho7fSoGh2Zgkq9HS7DlKxfBW2GEY0mp8
|
|
18
|
-
jeuxvBvh4xw/YuESVFbKedglaoNFf+aP44zL47Wn9QJcLqByGpTV472j238ObUFi
|
|
19
|
-
k47o+v4Qt7nkJDOcx7ic//uLTcb/1rv1SppYpKr3YJ5fLspzMMPpTQbkt2H8hLiZ
|
|
20
|
-
+1jj5GIoDgLi+/uxBgYQs78jEOIKkWO6EjwGUw==
|
|
21
|
-
-----END CERTIFICATE-----
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
-----BEGIN CERTIFICATE REQUEST-----
|
|
2
|
-
MIICmTCCAYECAQAwVDELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0
|
|
3
|
-
eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDEQMA4GA1UEAwwHcmVsdWtr
|
|
4
|
-
bzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKvz377M1Cz4wbmimgJN
|
|
5
|
-
ar9DEAmyv1S6Xn3xehAVefU3938k55KizLwE29vVFeyvmymw0lskS6fo48W1ShVz
|
|
6
|
-
NS2K9L31c1yFY+MRDXzDbZqItzCX+46t1/FaPTjIR8qZ6M1lcWtKGEBZEZ9zd+La
|
|
7
|
-
EPRjma1tLtPmKppjObhTlQNUWLNU+dKA8VcwCJq39VAa8EVy/kikGNc4kaQtlPOY
|
|
8
|
-
WVbrVPqb4wkZcXn0IsLq8vpAkKpClJRYb1QzTRHwvalDVvwcsphS4n6+nhZVjBjL
|
|
9
|
-
Pvr0E0bg4bciR2ogcoMVYFcVWYppSRf1oC6XgE6K0rLhcVzx67rneVuRWdEdvTVF
|
|
10
|
-
o/sCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCHkmw8bBBI9pOrlCrJ2u3sGdlx
|
|
11
|
-
3ZbW/+kGdsQ8Odb/pIHkLLKpu5yNLEey/U4EZyWSNewYDUKfS2FIyMN2c38QAex6
|
|
12
|
-
1Y9qPK74RzUB68ki7XKtp+GAGqVb0axxRe0IuBwc9d5jl6zjltcpdutAIIgXcJgg
|
|
13
|
-
8QPnfpz7Skhjjm/duTVp0rurWsPztQdDpkrcY3c49vuTLA5uKwfa//cPAOmVGwqq
|
|
14
|
-
TMICj+0M2S+bgg9Ksph1IsDxxuIm1aa2EFnF5XRbJn9aOSdyfBkKoZz9ttgu1hP4
|
|
15
|
-
+hPe8S3ekUyJiZAglSI1qJOkpyw14EDIhwJvE9FG5eN/mU8wS1/GU+vhZWKN
|
|
16
|
-
-----END CERTIFICATE REQUEST-----
|
|
Binary file
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
-----BEGIN PRIVATE KEY-----
|
|
2
|
-
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCr89++zNQs+MG5
|
|
3
|
-
opoCTWq/QxAJsr9Uul598XoQFXn1N/d/JOeSosy8BNvb1RXsr5spsNJbJEun6OPF
|
|
4
|
-
tUoVczUtivS99XNchWPjEQ18w22aiLcwl/uOrdfxWj04yEfKmejNZXFrShhAWRGf
|
|
5
|
-
c3fi2hD0Y5mtbS7T5iqaYzm4U5UDVFizVPnSgPFXMAiat/VQGvBFcv5IpBjXOJGk
|
|
6
|
-
LZTzmFlW61T6m+MJGXF59CLC6vL6QJCqQpSUWG9UM00R8L2pQ1b8HLKYUuJ+vp4W
|
|
7
|
-
VYwYyz769BNG4OG3IkdqIHKDFWBXFVmKaUkX9aAul4BOitKy4XFc8eu653lbkVnR
|
|
8
|
-
Hb01RaP7AgMBAAECggEAF22KShjmkwavf7HfnDmyYMMWhSO//XTJBA1/DSrylg5d
|
|
9
|
-
NQsGVsxslZ9vLyP4sT9PJjPWbUmO2fPuo1TVy6y0jZ3K8Qi8rNnrEphpBzB/Qe38
|
|
10
|
-
+5dxfu6WUebIGZucFca42SdITTm9VSMYNhU0O98XLp0AEV4jYlvlPmoPhrAzSM50
|
|
11
|
-
lEIuriNhqHuqZhXN0jPYI1jZDS5JVi2PlbgyO1125BBMsCMLfhW+wcme/Y/VAySc
|
|
12
|
-
pNkvK3aHeWJUXEeVKuNfn5878PqeD6ZPjl9Hyq3lj6yOauIO/PCdIwm+2qjzrYsy
|
|
13
|
-
IBhjFFEoMGofgz+KV7olZu9by38ZzhW7nZGGe+zbgQKBgQDmFyzzxz3/BF7FKTXL
|
|
14
|
-
v6uVNkGpMGH8EQE1H+YJXTiSaqf/3ZrsXyBsbA6YBanKBXcY/F0PhQ7e/rjtqaGU
|
|
15
|
-
OtekNTHSgosdbJgVX88EjfIa4/rbZPUsX6qRJBuDVOCcCZC1PyFBT2ehKYlIPHS0
|
|
16
|
-
klbXo57pYzgDnzrYPr6UWbCZewKBgQC/UMGNvqJXszYZe3hjd9Ek9oSJMThfpfXn
|
|
17
|
-
opNhCNHKZ8+xqry602TqIwyStYc7elB57R547ZR4kttT8iM1E7ZOoLRPP0r/FjOS
|
|
18
|
-
scpCAk5ouVG9RZaUvTIbvzdEifEOt1Vf0RgIG3Y4DBqtotNoymqyT5wzuxyJQm1E
|
|
19
|
-
683UVIbXgQKBgQCLPJ0UTI7kwtVCxIRsbum7WuDzLHcvHW84obwIEKSKXgaaHJWC
|
|
20
|
-
0rIBSoauUkcEHLiMozMBkEiGg2iPUaaY197k3NfwhtT+kleaH6dcHzXSNgH5QCfp
|
|
21
|
-
mV7ThCEuIW/mnRc3xyMtrYqNiWAtGYCaQTBSQA6LN2KPNo1ajOWxSnFG/wKBgQC2
|
|
22
|
-
9rBksq/nV4ihjidwWSI3S1stKVlUgA9QW3a/EgQwol9K9pJPyeN019gqZljSVQOp
|
|
23
|
-
10+RLwUS2r/O5H8vP47WW3KVZ1593emsnUNlJXd/R9wYOvjrfpTxXEmqzpEvFb4c
|
|
24
|
-
SIfHGRxSNaE99b5hNVQc+23TO1rrGhAOHcVXDw92AQKBgQDCMEcIcwHx+ahVZbEb
|
|
25
|
-
bAyWLwYxQFRStmYKbYBtEMFW39atRmc0wdAG0my/0cUyHUIfWbHvP5oTfyAthV9G
|
|
26
|
-
8G0qBk5fPhh6hfNRFMb2j1AqnZ3CadoBZq2HelTTUqt4UgU9Y4iDco+4ew34Uw76
|
|
27
|
-
2ki1bKXiJKkJYlk14AMrzckDUQ==
|
|
28
|
-
-----END PRIVATE KEY-----
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
-----BEGIN CERTIFICATE-----
|
|
2
|
-
MIIDiTCCAnGgAwIBAgIUeLTh5JgTZlG0dbwtCICijkg1MWwwDQYJKoZIhvcNAQEL
|
|
3
|
-
BQAwVDELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UE
|
|
4
|
-
CgwTRGVmYXVsdCBDb21wYW55IEx0ZDEQMA4GA1UEAwwHUmVsdWtrbzAeFw0yNDEx
|
|
5
|
-
MTMxNTM3MDBaFw00NDExMDgxNTM3MDBaMFQxCzAJBgNVBAYTAlhYMRUwEwYDVQQH
|
|
6
|
-
DAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQxEDAO
|
|
7
|
-
BgNVBAMMB1JlbHVra28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD4
|
|
8
|
-
PWQPjCCXOvZYUDpYhZHR4Nw0ErkZEZWtPMyoBnyGkYwqK1SrHCcIYQL8C22dN1rn
|
|
9
|
-
VdFvCVH13fQHz1SJ/v3jkS+9IiOUDenXpZP/G0pprTbLGh33aaQU53EqvO1T2CAA
|
|
10
|
-
zIAVdme0cihOB+KL2A5bDzP9fu+c0ddn+N++ZgcqBHMYmZKIGJv5QZ+i+/1xrGqQ
|
|
11
|
-
/znwV7RuBGms8fxA3x4Y4ELUzIHMpbXbQn95qC9u7ee4odQ5KjR1M0oocPKOYBGa
|
|
12
|
-
/Dqnhd3Wx0lHR3No8HgC4TBfxruhs+NZtRyInOTFr99TWbBx+zrDvxecM/5j/AnH
|
|
13
|
-
WHka8xMQSxJUeoXtlFT/AgMBAAGjUzBRMB0GA1UdDgQWBBRAo64Da82emF0q53wC
|
|
14
|
-
dj4wbFTmMDAfBgNVHSMEGDAWgBRAo64Da82emF0q53wCdj4wbFTmMDAPBgNVHRMB
|
|
15
|
-
Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQACdVeJ/CnXpY4t568bQRxIr+t3
|
|
16
|
-
IqeIqJVg1nt6OaB/EJPJil/lvJD8bjO5W5uXAnbkv26i0Q89KFZH3xKFHRmL/zR+
|
|
17
|
-
0YPcbi3LmQ+NY6LtH1GtBlRiobROfSp8/GxTrGxqMGHHxBdY+v8lPiK1LHTE99ik
|
|
18
|
-
cl8qF+DQMGeliPQcg9rLgXagymEc9oS3OgxjL7Al4/P8bLkdC/hxk+cEUFCXUX4v
|
|
19
|
-
z/PAFnHwEeJPiiNYG+hpQQRloVncynEwhBr/pGGMdLGaFBje41kn9Ss2anc+YaiW
|
|
20
|
-
DyoDLuQkCcRrUvc2dCGMZs0KaCv8i61QWGNy8suGq6nrXW9A57JhS7ak8xg9
|
|
21
|
-
-----END CERTIFICATE-----
|
|
Binary file
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
-----BEGIN PRIVATE KEY-----
|
|
2
|
-
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD4PWQPjCCXOvZY
|
|
3
|
-
UDpYhZHR4Nw0ErkZEZWtPMyoBnyGkYwqK1SrHCcIYQL8C22dN1rnVdFvCVH13fQH
|
|
4
|
-
z1SJ/v3jkS+9IiOUDenXpZP/G0pprTbLGh33aaQU53EqvO1T2CAAzIAVdme0cihO
|
|
5
|
-
B+KL2A5bDzP9fu+c0ddn+N++ZgcqBHMYmZKIGJv5QZ+i+/1xrGqQ/znwV7RuBGms
|
|
6
|
-
8fxA3x4Y4ELUzIHMpbXbQn95qC9u7ee4odQ5KjR1M0oocPKOYBGa/Dqnhd3Wx0lH
|
|
7
|
-
R3No8HgC4TBfxruhs+NZtRyInOTFr99TWbBx+zrDvxecM/5j/AnHWHka8xMQSxJU
|
|
8
|
-
eoXtlFT/AgMBAAECggEAeQhprIDsdP/dE4MOZ5G8XsHNa6BDWlsuCLivqi77cRsu
|
|
9
|
-
5XKaBhGkYFv4eg5SZAiUzF0Vz5cSPJf6vwISHHRUsqtbxNIL2ciM3sVO6t+SAQNg
|
|
10
|
-
x1cVDEgYJc8QaL+T0UD7nZgXzR8dgif0ydLjXL67hR9dAHhu+J2BcqKv6KPTU2LB
|
|
11
|
-
KWbCcLkY4PdCGwSNuvyPokc3Fo8U40Lm8tcWQ6sFV/+bv6+ShWhsb5Dx7sfVoijf
|
|
12
|
-
YikzFc7sEHb//nH2+C/FoCqneDPYl8lVH9zKYis4xWcA68bNwyfWpaQLXo32DKYq
|
|
13
|
-
rZxnwnawtU5b+t+TVp1DcCjOM3vaodeKI3Gqq5SjBQKBgQD/Sy33WOK+qelkvJxb
|
|
14
|
-
IcyP3U/ijNpWP3UidYGmmpTBP5UdaXyObX1G4nmfQjDad080jPpP/r350Tr0Xi2s
|
|
15
|
-
6wZBw0HoTZrZw5MQQKRQyh0Hg5VHHoHbD97UuLGGZ+Yc/hSWWfuDQHeV5Ami+VXD
|
|
16
|
-
TCYZGhtsjY9lUfUWYcsdcOA1fQKBgQD47TcVSC+3/8zKd2AAJeYrpx6wL/5X/4Zn
|
|
17
|
-
U0VeBxfF6MjQlu3avnwi6MxjkuB4KJAgWVHvJspJaS8ilIJN5qBsivphtfD0RV+d
|
|
18
|
-
UW9DCzoDUlU/AmNMD+stylgziSWoG9rzcY7P71izRE1tGGsgOXvZS5xUHzqWBwg6
|
|
19
|
-
MtYB4EQNKwKBgQCTUBVpKmBE9xTXbUKoD5vT1Df5mZ+PrzRvOvEiawa1cHQiMbGP
|
|
20
|
-
Gjz0/1CBBpfcKIaK42K5cFy9X++t/P5MTp4gqoRIgSd+yyz8buCiQc54fIRSMpdq
|
|
21
|
-
CgFiLGU8Eo4lYrQMgkXw2e1nj9vDsC698B331CnI/PKm26EaVjn3dh/anQKBgGxB
|
|
22
|
-
FWRu+TmmyBQA6EIIOVogmqr6pDz2xienQhKLOR57huGX0acAkhHIdiKTnIUE9vDq
|
|
23
|
-
h0Re9TgJw1LhjO1976RkqFDYBArnJJbQ9HcOqdMJ+kKlsjNA9QD773GyIitCueyH
|
|
24
|
-
JRluuH91o8pfBS+FcEPmqvy2fA8EzeIpe4JjWpTzAoGAQHoipuzDbhb02XMqioc+
|
|
25
|
-
UCsa6erj3kGrBUiFcvNutTG+oVq3qXOebOc9bCZcGHwsm0fgX5zk1XgY+IRfCWJY
|
|
26
|
-
X14DQfLMBi/vObDXH9BaoVvc50EPSBW0V5k2aXavJ6XelbBXSI33bzGb+5wAltI/
|
|
27
|
-
CFKf5ePEAi3jE69yYnTwbdc=
|
|
28
|
-
-----END PRIVATE KEY-----
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
206DA63B52317CCDF0AA22CB1423BEEAE6C6747B
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
-- Add up migration script here
|
|
2
|
-
CREATE EXTENSION moddatetime;
|
|
3
|
-
|
|
4
|
-
CREATE TABLE locks (
|
|
5
|
-
id uuid DEFAULT gen_random_uuid(),
|
|
6
|
-
lock_name VARCHAR NOT NULL,
|
|
7
|
-
creator VARCHAR,
|
|
8
|
-
ip INET,
|
|
9
|
-
expires_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + (10 ||' minutes')::interval ,
|
|
10
|
-
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
11
|
-
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
12
|
-
PRIMARY KEY (id),
|
|
13
|
-
UNIQUE(lock_name)
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
CREATE TRIGGER locks_moddatetime
|
|
17
|
-
BEFORE UPDATE ON locks
|
|
18
|
-
FOR EACH ROW
|
|
19
|
-
EXECUTE PROCEDURE moddatetime (updated_at);
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|