CI/CD hardening: lint, secret scan, coverage gate, auto CVE-fix PRs, GHCR + GitHub mirror publishing (#32)
CI / build-and-scan (push) Successful in 1m37s

- release changelog: commits rendered as description (link), divider lines dropped
- gitleaks secret scan and hadolint on every push/PR
- ruff lint/format gate (Python repos) with a pytest --cov-fail-under gate
- scheduled CRITICAL Trivy failures attempt an apk upgrade rebuild and open a follow-up PR if it clears the finding, instead of just failing red
- images also published to ghcr.io/djeex/<repo>
- a matching GitHub Release is created on the GitHub mirror, with a notice pointing back to this repo as the source of truth
This commit was merged in pull request #32.
This commit is contained in:
2026-08-26 15:43:40 +02:00
parent b3ed21eec2
commit 5a7a60d299
10 changed files with 356 additions and 135 deletions
+43 -19
View File
@@ -1,15 +1,29 @@
import time
import logging
import time
import requests
from env_config import (
DISCORD_WEBHOOK_URL, DISCORD_SERVER_NAME, DISCORD_ROLE_MAP, TEST_MODE, currency,
in_stock_title, out_of_stock_title, sku_change_title,
buy_now, price_label, time_label, footer, sku_description, imminent_drop
DISCORD_ROLE_MAP,
DISCORD_SERVER_NAME,
DISCORD_WEBHOOK_URL,
TEST_MODE,
buy_now,
currency,
footer,
imminent_drop,
in_stock_title,
out_of_stock_title,
price_label,
sku_change_title,
sku_description,
time_label,
)
AVATAR = "https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/ds_wh_pp.jpg"
THUMBNAIL = "https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/RTX5000.jpg"
# In stock
def send_discord_notification(gpu_name, product_link, products_price):
timestamp = int(time.time())
@@ -24,17 +38,20 @@ def send_discord_notification(gpu_name, product_link, products_price):
"author": {"name": "Nvidia Founder Editions"},
"fields": [
{"name": price_label, "value": f"`{currency}{products_price}`", "inline": True},
{"name": time_label, "value": f"<t:{timestamp}:d> <t:{timestamp}:T>", "inline": True}
{"name": time_label, "value": f"<t:{timestamp}:d> <t:{timestamp}:T>", "inline": True},
],
"description": buy_now.format(product_link=product_link),
"footer": {"text": footer.format(DISCORD_SERVER_NAME=DISCORD_SERVER_NAME), "icon_url": AVATAR}
"footer": {
"text": footer.format(DISCORD_SERVER_NAME=DISCORD_SERVER_NAME),
"icon_url": AVATAR,
},
}
payload = {
"content": DISCORD_ROLE_MAP.get(gpu_name, "@everyone"),
"username": "NviBot",
"avatar_url": AVATAR,
"embeds": [embed]
"embeds": [embed],
}
try:
@@ -46,6 +63,7 @@ def send_discord_notification(gpu_name, product_link, products_price):
except Exception as e:
logging.error(f"🚨 Error sending webhook: {e}")
# Out of stock
def send_out_of_stock_notification(gpu_name, product_link, products_price):
timestamp = int(time.time())
@@ -59,15 +77,16 @@ def send_out_of_stock_notification(gpu_name, product_link, products_price):
"thumbnail": {"url": THUMBNAIL},
"url": product_link,
"author": {"name": "Nvidia Founder Editions"},
"footer": {"text": footer.format(DISCORD_SERVER_NAME=DISCORD_SERVER_NAME), "icon_url": AVATAR},
"fields": [{"name": time_label, "value": f"<t:{timestamp}:d> <t:{timestamp}:T>", "inline": True}]
"footer": {
"text": footer.format(DISCORD_SERVER_NAME=DISCORD_SERVER_NAME),
"icon_url": AVATAR,
},
"fields": [
{"name": time_label, "value": f"<t:{timestamp}:d> <t:{timestamp}:T>", "inline": True}
],
}
payload = {
"username": "NviBot",
"avatar_url": AVATAR,
"embeds": [embed]
}
payload = {"username": "NviBot", "avatar_url": AVATAR, "embeds": [embed]}
try:
response = requests.post(DISCORD_WEBHOOK_URL, json=payload)
@@ -78,6 +97,7 @@ def send_out_of_stock_notification(gpu_name, product_link, products_price):
except Exception as e:
logging.error(f"🚨 Error sending webhook: {e}")
# SKU change
def send_sku_change_notification(gpu_name, old_sku, new_sku, product_link):
timestamp = int(time.time())
@@ -90,15 +110,20 @@ def send_sku_change_notification(gpu_name, old_sku, new_sku, product_link):
"url": product_link,
"description": sku_description.format(old_sku=old_sku, new_sku=new_sku),
"color": 16776960,
"footer": {"text": footer.format(DISCORD_SERVER_NAME=DISCORD_SERVER_NAME), "icon_url": AVATAR},
"fields": [{"name": time_label, "value": f"<t:{timestamp}:d> <t:{timestamp}:T>", "inline": True}]
"footer": {
"text": footer.format(DISCORD_SERVER_NAME=DISCORD_SERVER_NAME),
"icon_url": AVATAR,
},
"fields": [
{"name": time_label, "value": f"<t:{timestamp}:d> <t:{timestamp}:T>", "inline": True}
],
}
payload = {
"content": imminent_drop.format(DISCORD_ROLE=DISCORD_ROLE_MAP.get(gpu_name, '@everyone')),
"content": imminent_drop.format(DISCORD_ROLE=DISCORD_ROLE_MAP.get(gpu_name, "@everyone")),
"username": "NviBot",
"avatar_url": AVATAR,
"embeds": [embed]
"embeds": [embed],
}
try:
@@ -109,4 +134,3 @@ def send_sku_change_notification(gpu_name, old_sku, new_sku, product_link):
logging.error(f"❌ Webhook error: {response.status_code} - {response.text}")
except Exception as e:
logging.error(f"🚨 Error sending webhook: {e}")