Add missing docker builders

This commit is contained in:
Guilhem Lavaux 2024-12-08 08:33:39 +01:00
parent a802ecce7a
commit 4032ad5882
11 changed files with 645 additions and 0 deletions

View File

@ -0,0 +1,8 @@
FROM php:8.2-apache
RUN apt-get update && apt-get install -y zlib1g-dev libwebp-dev libavif-dev libpng-dev libjpeg-dev libzip-dev ruby && rm -rf /var/lib/apt/lists/*
RUN gem install kramdown
RUN docker-php-ext-install pdo pdo_mysql gd zip
RUN a2enmod rewrite

View File

@ -0,0 +1,3 @@
podman pull php:8.2-apache
podman build -t glvx/php .
podman push glvx/php docker://docker.io/glvx/php:8.2b

View File

@ -0,0 +1,14 @@
FROM ubuntu:24.04
RUN apt-get update && apt-get install --no-upgrade -y curl python3 python3-pip python3-venv git git-lfs ssh
COPY updater.sh /updater.sh
COPY webhook /opt/webhook
RUN python3 -m venv /opt/webhook/.venv && \
/opt/webhook/.venv/bin/python3 -m ensurepip && \
/opt/webhook/.venv/bin/python3 -m pip install -r /opt/webhook/requirements.txt
COPY webhook-runner.sh /webhook-runner.sh
ENTRYPOINT /updater.sh

View File

@ -0,0 +1,2 @@
podman build -t glvx/web-updater .
podman push glvx/web-updater docker://docker.io/glvx/web-updater:241204-2

View File

@ -0,0 +1,24 @@
#!/bin/bash
if test -z "${GL_URL}"; then
echo "No URL defined"
exit 1
fi
test -d /web/.attic || mkdir /web/.attic
if test -f /web/.attic/SNAPID; then
read snapid < /web/.attic/SNAPID
let snapid=snapid+1
echo ${snapid} > /web/.attic/SNAPID
mkdir /web/.attic/snap-${snapid}
else
echo 0 > /web/.attic/SNAPID
let snapid=0
mkdir /web/.attic/snap-${snapid}
fi
find /web -maxdepth 1 ! "(" -name ".attic" -o -wholename "/web" ")" -print0 | xargs -n 1 -0 mv -t /web/.attic/snap-${snapid}
curl "${GL_URL}" | tar -C /web --strip-components 1 -zxvf -

View File

@ -0,0 +1,9 @@
#!/bin/bash
GIT_AUTH_MODE=$1
export GIT_AUTH_MODE
source /opt/webhook/.venv/bin/activate
cd /opt/webhook
gunicorn --bind 0.0.0.0:8000 gitea-webhook-handler:app

View File

@ -0,0 +1,343 @@
from flask import Flask, request, jsonify
import hmac
import hashlib
import os
from functools import wraps
import base64
import logging
import subprocess
from datetime import datetime
from enum import Enum
app = Flask(__name__)
# Configuration
# In production, use proper secret management
WEBHOOK_SECRET = os.environ['WEBHOOK_SECRET']
API_USERNAME = os.environ['API_USERNAME']
API_PASSWORD = os.environ['API_PASSWORD']
DATA_DIR = os.environ['DATA_DIR']
GIT_AUTH_MODE = os.environ['GIT_AUTH_MODE']
if GIT_AUTH_MODE == 'http':
auth_option = []
elif GIT_AUTH_MODE == 'ssh':
auth_option = ['--config core.sshCommand="ssh -i /ssh/ssh-key" -o StrictHostKeyChecking=accept-new']
else:
raise ValueError("Invalid GIT_AUTH_MODE")
# Setup logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('webhook.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
class GitProvider(Enum):
GITEA = "gitea"
GITLAB = "gitlab"
UNKNOWN = "unknown"
GITEA_EVENTS = {
'push': 'Push events',
'create': 'Branch or tag creation',
'delete': 'Branch or tag deletion',
'pull_request': 'Pull request events',
'issues': 'Issues events'
}
class GitOperationError(Exception):
"""Custom exception for git operations"""
pass
def detect_git_provider():
"""
Detect whether the webhook is from Gitea or GitLab based on headers
"""
if request.headers.get('X-Gitea-Event'):
return GitProvider.GITEA
elif request.headers.get('X-Gitlab-Event'):
return GitProvider.GITLAB
return GitProvider.UNKNOWN
def verify_signature(f):
@wraps(f)
def decorated_function(*args, **kwargs):
provider = detect_git_provider()
payload_body = request.get_data()
if provider == GitProvider.GITEA:
signature = request.headers.get('X-Gitea-Signature')
if not signature:
return jsonify({'error': 'No Gitea signature provided'}), 401
expected_signature = hmac.new(
WEBHOOK_SECRET.encode('utf-8'),
payload_body,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected_signature):
return jsonify({'error': 'Invalid Gitea signature'}), 401
elif provider == GitProvider.GITLAB:
token = request.headers.get('X-Gitlab-Token')
if not token:
return jsonify({'error': 'No GitLab token provided'}), 401
if not hmac.compare_digest(token, WEBHOOK_SECRET):
return jsonify({'error': 'Invalid GitLab token'}), 401
else:
return jsonify({'error': 'Unknown Git provider'}), 400
return f(*args, **kwargs)
return decorated_function
def execute_git_pull(repo_path):
"""
Execute git pull in the specified repository path
Returns tuple of (success, message)
"""
try:
# Verify the directory exists and is a git repository
if not os.path.exists(repo_path):
raise GitOperationError(f"Directory does not exist: {repo_path}")
if not os.path.exists(os.path.join(repo_path, '.git')):
raise GitOperationError(f"Not a git repository: {repo_path}")
# Create backup of current state
current_commit = subprocess.check_output(
['git', 'rev-parse', 'HEAD'],
cwd=repo_path,
stderr=subprocess.PIPE
).decode().strip()
# Execute git pull
result = subprocess.run(
['git', 'pull'] + auth_option,
cwd=repo_path,
capture_output=True,
text=True,
timeout=300 # 5-minute timeout
)
if result.returncode != 0:
raise GitOperationError(f"Git pull failed: {result.stderr}")
new_commit = subprocess.check_output(
['git', 'rev-parse', 'HEAD'],
cwd=repo_path,
stderr=subprocess.PIPE
).decode().strip()
return True, {
'message': 'Git pull successful',
'output': result.stdout,
'previous_commit': current_commit,
'new_commit': new_commit
}
except subprocess.TimeoutExpired:
raise GitOperationError("Git pull operation timed out")
except subprocess.CalledProcessError as e:
raise GitOperationError(f"Git command failed: {e.stderr.decode() if e.stderr else str(e)}")
except Exception as e:
raise GitOperationError(f"Unexpected error: {str(e)}")
def require_basic_auth(f):
@wraps(f)
def decorated_function(*args, **kwargs):
auth_header = request.headers.get('Authorization')
if not auth_header:
return authenticate()
try:
auth_type, auth_string = auth_header.split(' ', 1)
if auth_type.lower() != 'basic':
return authenticate()
# Decode base64 credentials
credentials = base64.b64decode(auth_string).decode('utf-8')
username, password = credentials.split(':', 1)
if not (username == API_USERNAME and password == API_PASSWORD):
return authenticate()
except (ValueError, base64.binascii.Error):
return authenticate()
return f(*args, **kwargs)
return decorated_function
def authenticate():
"""Sends a 401 response that enables basic auth"""
return jsonify({'error': 'Authentication required'}), 401, {
'WWW-Authenticate': 'Basic realm="Login Required"'
}
def parse_push_event(provider, payload):
"""
Parse push event payload based on the provider
Returns standardized data structure
"""
try:
if provider == GitProvider.GITEA:
return {
'repo_name': payload['repository']['full_name'].split('/')[-1],
'repo_full_name': payload['repository']['full_name'],
'branch': payload['ref'].split('/')[-1],
'commits': payload['commits'],
'default_branch': payload['repository']['default_branch']
}
elif provider == GitProvider.GITLAB:
return {
'repo_name': payload['project']['web_url'].split('/')[-1],
'repo_full_name': payload['project']['name'],
'branch': payload['ref'].split('/')[-1],
'commits': payload['commits'],
'default_branch': payload['project']['default_branch']
}
else:
raise ValueError("Unknown git provider")
except KeyError as e:
raise KeyError(f"Missing required field in payload: {str(e)}")
@app.route('/webhook', methods=['POST'])
@require_basic_auth
@verify_signature
def webhook():
if not request.is_json:
return jsonify({'error': 'Content type must be application/json'}), 400
provider = detect_git_provider()
payload = request.get_json()
# Determine event type based on provider
if provider == GitProvider.GITEA:
event_type = request.headers.get('X-Gitea-Event')
elif provider == GitProvider.GITLAB:
event_type = request.headers.get('X-Gitlab-Event')
else:
return jsonify({'error': 'Unknown git provider'}), 400
# Normalize event types between Gitea and GitLab
if provider == GitProvider.GITLAB and event_type == 'Push Hook':
event_type = 'push'
if event_type.lower() == 'push':
return handle_push(provider, payload)
else:
logger.info(f"Received unhandled event type: {event_type} from {provider.value}")
return jsonify({'status': 'received', 'event': event_type, 'provider': provider.value}), 200
def handle_push(provider, payload):
"""Handle push events"""
try:
# Parse the payload according to the provider's format
data = parse_push_event(provider, payload)
logger.info(f"Push to {data['repo_full_name']} on branch {data['branch']} via {provider.value}")
logger.info(f"Number of commits: {len(data['commits'])}")
# Only process pushes to the default branch
if data['branch'] != data['default_branch']:
logger.info(f"Skipping pull for non-default branch: {data['branch']}")
return jsonify({
'status': 'skipped',
'event': 'push',
'provider': provider.value,
'reason': f"Push was to non-default branch {data['branch']}"
}), 200
# Construct the repository path
repo_path = DATA_DIR #os.path.join(DATA_DIR, data['repo_name'])
try:
success, result = execute_git_pull(repo_path)
logger.info(f"Git pull result for {data['repo_name']}: {result['message']}")
response_data = {
'status': 'success',
'event': 'push',
'provider': provider.value,
'repo': data['repo_full_name'],
'branch': data['branch'],
'commits_count': len(data['commits']),
'git_pull': result
}
except GitOperationError as e:
logger.error(f"Git pull failed for {data['repo_name']}: {str(e)}")
response_data = {
'status': 'error',
'event': 'push',
'provider': provider.value,
'repo': data['repo_full_name'],
'branch': data['branch'],
'commits_count': len(data['commits']),
'error': str(e)
}
return jsonify(response_data), 200
except KeyError as e:
logger.error(f"Invalid payload structure: {str(e)}")
return jsonify({'error': f'Invalid payload structure: {str(e)}'}), 400
#def handle_pull_request(payload):
# """Handle pull request events"""
# try:
# action = payload['action']
# pr_number = payload['number']
# repo = payload['repository']['full_name']
#
# logger.info(f"Pull request #{pr_number} {action} in {repo}")
#
# return jsonify({
# 'status': 'success',
# 'event': 'pull_request',
# 'action': action,
# 'pr_number': pr_number,
# 'repo': repo
# }), 200
# except KeyError as e:
# logger.error(f"Invalid payload structure: {str(e)}")
# return jsonify({'error': f'Invalid payload structure: {str(e)}'}), 400
#
#def handle_issues(payload):
# """Handle issues events"""
# try:
# action = payload['action']
# issue_number = payload['issue']['number']
# repo = payload['repository']['full_name']
#
# logger.info(f"Issue #{issue_number} {action} in {repo}")
#
# return jsonify({
# 'status': 'success',
# 'event': 'issues',
# 'action': action,
# 'issue_number': issue_number,
# 'repo': repo
# }), 200
# except KeyError as e:
# logger.error(f"Invalid payload structure: {str(e)}")
# return jsonify({'error': f'Invalid payload structure: {str(e)}'}), 400
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

211
docker/deployer_docker/webhook/poetry.lock generated Normal file
View File

@ -0,0 +1,211 @@
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
[[package]]
name = "blinker"
version = "1.9.0"
description = "Fast, simple object-to-object and broadcast signaling"
optional = false
python-versions = ">=3.9"
files = [
{file = "blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc"},
{file = "blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf"},
]
[[package]]
name = "click"
version = "8.1.7"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
files = [
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
]
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]]
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "flask"
version = "3.1.0"
description = "A simple framework for building complex web applications."
optional = false
python-versions = ">=3.9"
files = [
{file = "flask-3.1.0-py3-none-any.whl", hash = "sha256:d667207822eb83f1c4b50949b1623c8fc8d51f2341d65f72e1a1815397551136"},
{file = "flask-3.1.0.tar.gz", hash = "sha256:5f873c5184c897c8d9d1b05df1e3d01b14910ce69607a117bd3277098a5836ac"},
]
[package.dependencies]
blinker = ">=1.9"
click = ">=8.1.3"
itsdangerous = ">=2.2"
Jinja2 = ">=3.1.2"
Werkzeug = ">=3.1"
[package.extras]
async = ["asgiref (>=3.2)"]
dotenv = ["python-dotenv"]
[[package]]
name = "gunicorn"
version = "23.0.0"
description = "WSGI HTTP Server for UNIX"
optional = false
python-versions = ">=3.7"
files = [
{file = "gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"},
{file = "gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"},
]
[package.dependencies]
packaging = "*"
[package.extras]
eventlet = ["eventlet (>=0.24.1,!=0.36.0)"]
gevent = ["gevent (>=1.4.0)"]
setproctitle = ["setproctitle"]
testing = ["coverage", "eventlet", "gevent", "pytest", "pytest-cov"]
tornado = ["tornado (>=0.2)"]
[[package]]
name = "itsdangerous"
version = "2.2.0"
description = "Safely pass data to untrusted environments and back."
optional = false
python-versions = ">=3.8"
files = [
{file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"},
{file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"},
]
[[package]]
name = "jinja2"
version = "3.1.4"
description = "A very fast and expressive template engine."
optional = false
python-versions = ">=3.7"
files = [
{file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
{file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
]
[package.dependencies]
MarkupSafe = ">=2.0"
[package.extras]
i18n = ["Babel (>=2.7)"]
[[package]]
name = "markupsafe"
version = "3.0.2"
description = "Safely add untrusted strings to HTML/XML markup."
optional = false
python-versions = ">=3.9"
files = [
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
{file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"},
{file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"},
{file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"},
{file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"},
{file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"},
{file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"},
{file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"},
{file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"},
{file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"},
{file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"},
{file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"},
{file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"},
{file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"},
{file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"},
{file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"},
{file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"},
{file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"},
{file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"},
{file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"},
{file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"},
{file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"},
{file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"},
{file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"},
{file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"},
{file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"},
{file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"},
{file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"},
{file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"},
{file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"},
{file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"},
{file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"},
{file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"},
{file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"},
{file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"},
{file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"},
{file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"},
{file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"},
{file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"},
{file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"},
{file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"},
{file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"},
{file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"},
{file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"},
{file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"},
{file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"},
{file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"},
{file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"},
{file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"},
{file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"},
]
[[package]]
name = "packaging"
version = "24.2"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
files = [
{file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"},
{file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
]
[[package]]
name = "werkzeug"
version = "3.1.3"
description = "The comprehensive WSGI web application library."
optional = false
python-versions = ">=3.9"
files = [
{file = "werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e"},
{file = "werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746"},
]
[package.dependencies]
MarkupSafe = ">=2.1.1"
[package.extras]
watchdog = ["watchdog (>=2.3)"]
[metadata]
lock-version = "2.0"
python-versions = "^3.12"
content-hash = "586b9c67ea1e0facc248baa9dd3ad0739dfacc8f6916dcc12e084d64e068dee4"

View File

@ -0,0 +1,16 @@
[tool.poetry]
name = "webhook"
version = "0.1.0"
description = ""
authors = ["Guilhem Lavaux <guilhem.lavaux@iap.fr>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.12"
flask = "^3.1.0"
gunicorn = "^23.0.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

View File

@ -0,0 +1,10 @@
blinker==1.9.0 ; python_version >= "3.12" and python_version < "4.0"
click==8.1.7 ; python_version >= "3.12" and python_version < "4.0"
colorama==0.4.6 ; python_version >= "3.12" and python_version < "4.0" and platform_system == "Windows"
flask==3.1.0 ; python_version >= "3.12" and python_version < "4.0"
gunicorn==23.0.0 ; python_version >= "3.12" and python_version < "4.0"
itsdangerous==2.2.0 ; python_version >= "3.12" and python_version < "4.0"
jinja2==3.1.4 ; python_version >= "3.12" and python_version < "4.0"
markupsafe==3.0.2 ; python_version >= "3.12" and python_version < "4.0"
packaging==24.2 ; python_version >= "3.12" and python_version < "4.0"
werkzeug==3.1.3 ; python_version >= "3.12" and python_version < "4.0"

View File

@ -0,0 +1,5 @@
2024-11-19 07:53:50,765 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://192.168.2.116:5000
2024-11-19 07:53:50,765 - INFO - Press CTRL+C to quit