Compare commits

...
Sign in to create a new pull request.

19 commits

Author SHA1 Message Date
a545c66c3e
Configuration file example added.
All checks were successful
Build and Push Docker Image / build (push) Successful in 14s
2026-01-23 17:43:23 +01:00
9d59f0b318
Alpine package name fixed.
All checks were successful
Build and Push Docker Image / build (push) Successful in 2m24s
2026-01-18 20:14:10 +01:00
78a76a5a3f
Dockerfile image version fixed
Some checks failed
Build and Push Docker Image / build (push) Failing after 18s
2026-01-18 20:13:04 +01:00
eada22fb21
Dockerfile typo
Some checks failed
Build and Push Docker Image / build (push) Failing after 14s
2026-01-18 20:12:00 +01:00
9c9850395f
Use Alpine 3.23 as cabuilder
Some checks failed
Build and Push Docker Image / build (push) Failing after 11s
2026-01-18 20:11:14 +01:00
4de4c398c6
Build-Dependency py3-requests
Some checks failed
Build and Push Docker Image / build (push) Failing after 20s
2026-01-18 20:00:13 +01:00
60231cb20d
Wofkload Typo fixed.
Some checks failed
Build and Push Docker Image / build (push) Failing after 32s
2026-01-18 19:58:44 +01:00
dc3ab7e3c0
Workflow variables fixed
Some checks failed
Build and Push Docker Image / build (push) Failing after 9s
2026-01-18 19:57:20 +01:00
943f488bbe
New Workflow Variable REGISTRY_HOST (custom)
Some checks failed
Build and Push Docker Image / build (push) Failing after 9s
2026-01-18 19:53:27 +01:00
497468c8e9
TLS-Verify for checkout-Action disabled.
Some checks failed
Build and Push Docker Image / build (push) Failing after 9s
2026-01-18 19:49:59 +01:00
ecba05f9e7
Allow actions on dev-Branch
Some checks failed
Build and Push Docker Image / build (push) Failing after 32s
2026-01-18 19:32:20 +01:00
8333305c55
Gitea Workflow eingefügt. 2026-01-18 19:31:23 +01:00
23651e0e2e
Download Let's Encrypt CA-Certificates 2026-01-18 19:11:46 +01:00
8c13a92fa3
Additional Python dependencies added. 2026-01-18 19:02:22 +01:00
9506e727ad
Build for nuxi based Websites 2024-12-04 22:35:12 +01:00
ce035d9186
Add configuration-File support. 2024-12-04 21:44:12 +01:00
a85e2a090e
Add nodejs and npm to image 2024-12-04 21:09:55 +01:00
ce60b815c9
Add node- and npm-version output to test stage 2024-12-04 21:07:00 +01:00
c972a5982e
Create Image-Tag from CI_COMMIT_REF_SLUG 2024-12-04 21:02:06 +01:00
8 changed files with 275 additions and 14 deletions

View file

@ -0,0 +1,45 @@
name: Build and Push Docker Image
on:
push:
branches: [ main, dev ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
env:
GIT_SSL_NO_VERIFY: true
- name: Login to Registry
uses: docker/login-action@v2
with:
registry: ${{ vars.REGISTRY_HOST }}
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build Docker Image
env:
BRANCH_NAME: ${{ github.ref_name }}
SHORT_HASH: ${{ github.sha }}
run: |
# Build the image with the commit hash tag
docker build --build-arg BUILD_IDENTIFIER=${SHORT_HASH:0:5} -t ${{ vars.REGISTRY_HOST }}/${GITHUB_REPOSITORY}:${BRANCH_NAME}-${SHORT_HASH:0:5} .
# Tag the same image as "latest"
docker tag ${{ vars.REGISTRY_HOST }}/${GITHUB_REPOSITORY}:${BRANCH_NAME}-${SHORT_HASH:0:5} ${{ vars.REGISTRY_HOST }}/${GITHUB_REPOSITORY}:${BRANCH_NAME}-latest
- name: Push Docker Images
env:
BRANCH_NAME: ${{ github.ref_name }}
SHORT_HASH: ${{ github.sha }}
run: |
docker push ${{ vars.REGISTRY_HOST }}/${GITHUB_REPOSITORY}:${BRANCH_NAME}-${SHORT_HASH:0:5}
docker push ${{ vars.REGISTRY_HOST }}/${GITHUB_REPOSITORY}:${BRANCH_NAME}-latest
- name: Log out from registry
if: always()
run: docker logout ${{ vars.REGISTRY_HOST }}

View file

@ -27,6 +27,8 @@ test:
stage: test stage: test
image: "$CI_REGISTRY_IMAGE:job-$CI_PIPELINE_ID" image: "$CI_REGISTRY_IMAGE:job-$CI_PIPELINE_ID"
script: script:
- node --version
- npm --version
- python --version - python --version
- nikola --version - nikola --version
- pip --version - pip --version
@ -37,8 +39,9 @@ deploy:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script: script:
- docker pull $CI_REGISTRY_IMAGE:job-$CI_PIPELINE_ID - docker pull $CI_REGISTRY_IMAGE:job-$CI_PIPELINE_ID
- docker tag $CI_REGISTRY_IMAGE:job-$CI_PIPELINE_ID $CI_REGISTRY_IMAGE:latest - docker tag $CI_REGISTRY_IMAGE:job-$CI_PIPELINE_ID $CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG:-latest}
- docker push $CI_REGISTRY_IMAGE:latest - echo "deploying $CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG:-latest}"
- docker push $CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG:-latest}
include: include:
- template: Security/SAST.gitlab-ci.yml - template: Security/SAST.gitlab-ci.yml
- template: Security/Container-Scanning.gitlab-ci.yml - template: Security/Container-Scanning.gitlab-ci.yml

View file

@ -1,13 +1,21 @@
FROM docker.io/library/alpine:3.23 AS cabuilder
RUN apk add --no-cache ca-certificates python3 py3-requests
ADD bin/fetch_letsencrypt_ca_certs.py /usr/local/bin/fetch_letsencrypt_ca_certs.py
RUN /usr/local/bin/fetch_letsencrypt_ca_certs.py /usr/local/share/ca-certificates/
RUN update-ca-certificates
FROM docker.io/library/python:3.11-alpine FROM docker.io/library/python:3.11-alpine
RUN apk --no-cache add sshpass openssh-client lftp; mkdir -p /opt/app RUN apk --no-cache add sshpass openssh-client lftp nodejs npm; mkdir -p /opt/app
WORKDIR /opt/app WORKDIR /opt/app
ADD requirements.txt /root/ ADD requirements.txt /root/
ADD Dockerfile /root/ ADD Dockerfile /root/
ADD bin/*.sh /usr/local/bin/ ADD bin/*.sh /usr/local/bin/
COPY --from=cabuilder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
# ignore "Running pip as root" warning # ignore "Running pip as root" warning
ENV PIP_ROOT_USER_ACTION=ignore ENV PIP_ROOT_USER_ACTION=ignore
ENV REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
RUN chmod 755 /usr/local/bin/*.sh && pip install -r /root/requirements.txt && pip freeze && rm -Rf "$(pip cache dir)" RUN chmod 755 /usr/local/bin/*.sh && pip install -r /root/requirements.txt && pip freeze && rm -Rf "$(pip cache dir)"

View file

@ -1,6 +1,6 @@
# deployment-helper für Nikola based Websites # deployment-helper für Nikola based Websites
# ENV-Variables ## ENV-Variables
* LFTP_PASSWORD (Deployment-Passwort for sftp-Upload) * LFTP_PASSWORD (Deployment-Passwort for sftp-Upload)
* SSH_HOST (Deployment-Host for sftp-Upload) * SSH_HOST (Deployment-Host for sftp-Upload)
@ -11,6 +11,27 @@
This image is based on the python:3.11-alpine image and includes additional This image is based on the python:3.11-alpine image and includes additional
Python-packages for building nikola-sites. Python-packages for building nikola-sites.
## Configure your project
| Variable | Default | Description |
| --------------------------- | --------------- | ---------------------------------------- |
| DEPLOY_HELPER_ENABLE_NIKOLA | true | Build Nikola-Website in `website/` |
| DEPLOY_HELPER_ENABLE_NODE | false | Enable nodejs Build in `node/` |
| DEPLOY_HELPER_CONTENT_DIR | website/output/ | Default Content-Directory for publishing |
Create a configuration file in your git-repo: `.deployment-helper`:
```
DEPLOY_HELPER_ENABLE_NIKOLA=false
DEPLOY_HELPER_ENABLE_NODE=true
DEPLOY_HELPER_CONTENT_DIR="node/.output/public/"
```
This example disables the niko build and enables node. The finished
website is copied from the `node/.output/public/` directory to the
target server.
## lftp for sftp-Uploads ## lftp for sftp-Uploads
This image includes `lftp` to upload files to a sftp-server and use This image includes `lftp` to upload files to a sftp-server and use

View file

@ -1,18 +1,76 @@
#!/bin/sh #!/bin/sh
# Default configurations:
DEPLOY_HELPER_ENABLE_NIKOLA=true
DEPLOY_HELPER_ENABLE_NODE=false
if test -f .deployment-helper
then
# shellcheck source=/dev/null
. .deployment-helper
fi
if $DEPLOY_HELPER_ENABLE_NODE
then
if ! command -v node >/dev/null 2>&1
then
echo "node not found" 1>&2
exit 1
fi
if ! command -v npm >/dev/null 2>&1
then
echo "npm not found" 1>&2
exit 1
fi
if ! test -d node
then
echo "Node directory not found" 1>&2
exit 1
fi
cd node || { echo 'Directory "node" not found'; exit 1;}
if ! npm install
then
echo "Error installing node-dependencies" 1>&2
exit 1
fi
if test -f nuxt.config.ts
then
# Build for nuxi based Sites
if ! npx nuxi build
then
echo "Error nuxi build" 1>&2
exit 1
fi
if ! npx nuxi generate
then
echo "Error nuxi generate" 1>&2
exit 1
fi
else
echo "No supportet node website type found" 1>&2
exit 1
fi
cd ..
fi
if $DEPLOY_HELPER_ENABLE_NIKOLA
then
if ! test -d website if ! test -d website
then then
echo "Website directory not found" echo "Website directory not found" 1>&2
exit 1 exit 1
fi fi
if ! command -v nikola >/dev/null 2>&1 if ! command -v nikola >/dev/null 2>&1
then then
echo "nikola command not found" echo "nikola command not found" 1>&2
exit 1 exit 1
fi fi
cd website || { echo 'Directory "website" not found'; exit 1;}
cd website
nikola build nikola build
cd ..
fi
exit "$?" exit "$?"

View file

@ -1,7 +1,16 @@
#!/bin/sh #!/bin/sh
# Default configurations:
DEPLOY_HELPER_CONTENT_DIR="website/output"
if ! test -d website/output if test -f .deployment-helper
then
# shellcheck source=/dev/null
. .deployment-helper
fi
if ! test -d "${DEPLOY_HELPER_CONTENT_DIR}"
then then
echo "Website-Build not found" echo "Website-Build not found"
exit 1 exit 1
@ -16,6 +25,9 @@ then
fi fi
lftp -e 'set sftp:auto-confirm yes; mirror -R ./website/output/ ./web/; bye' --env-password -u ${SSH_USER} sftp://${SSH_HOST} lftp -e "set sftp:auto-confirm yes; mirror -R ${DEPLOY_HELPER_CONTENT_DIR} ./web/; bye" \
--env-password \
-u ${SSH_USER} \
sftp://${SSH_HOST}

109
bin/fetch_letsencrypt_ca_certs.py Executable file
View file

@ -0,0 +1,109 @@
#!/usr/bin/env python3
import os
import sys
import requests
from html.parser import HTMLParser
from urllib.parse import urljoin
LETSENCRYPT_CERT_PAGE = "https://letsencrypt.org/certificates/"
DEFAULT_TARGET_DIR = "./letsencrypt-ca"
class PemLinkParser(HTMLParser):
def __init__(self):
super().__init__()
self.pem_links = set()
def handle_starttag(self, tag, attrs):
if tag.lower() != "a":
return
for attr, value in attrs:
if attr == "href" and value.lower().endswith(".pem"):
self.pem_links.add(value)
def fetch_certificate_page():
resp = requests.get(LETSENCRYPT_CERT_PAGE, timeout=15)
resp.raise_for_status()
return resp.text
def extract_pem_links(html):
parser = PemLinkParser()
parser.feed(html)
return sorted(
urljoin(LETSENCRYPT_CERT_PAGE, link)
for link in parser.pem_links
)
def download_and_store(url, target_dir):
base_name = os.path.basename(url)
# Zielname = .crt statt .pem
target_name = os.path.splitext(base_name)[0] + ".crt"
target_path = os.path.join(target_dir, target_name)
if os.path.exists(target_path):
print(f"[=] Bereits vorhanden: {target_name}")
return target_name
print(f"[+] Lade herunter: {base_name}")
resp = requests.get(url, timeout=15)
resp.raise_for_status()
if b"BEGIN CERTIFICATE" not in resp.content:
print(f"[!] Ungültiges Zertifikat: {base_name}")
return None
# Direkt als .crt speichern (PEM-Inhalt)
with open(target_path, "wb") as f:
f.write(resp.content)
return target_name
def list_local_crt_files(target_dir):
return {
f for f in os.listdir(target_dir)
if f.lower().endswith(".crt")
}
def main():
target_dir = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_TARGET_DIR
os.makedirs(target_dir, exist_ok=True)
print(f"[*] Zielverzeichnis: {os.path.abspath(target_dir)}")
print("[*] Format: PEM-Inhalt mit .crt-Endung")
html = fetch_certificate_page()
pem_urls = extract_pem_links(html)
# Remote-Dateinamen im .crt-Format
remote_files = {
os.path.splitext(os.path.basename(url))[0] + ".crt"
for url in pem_urls
}
for url in pem_urls:
download_and_store(url, target_dir)
local_files = list_local_crt_files(target_dir)
orphaned = sorted(local_files - remote_files)
print("\n" + "=" * 60)
if orphaned:
print("[!] Lokal vorhanden, aber nicht mehr gelistet:")
for f in orphaned:
print(f" - {f}")
else:
print("[✓] Keine veralteten Dateien gefunden")
print("=" * 60)
print("[✓] Fertig.")
if __name__ == "__main__":
main()

View file

@ -5,3 +5,8 @@ Jinja2
aiohttp aiohttp
watchdog watchdog
python-dotenv python-dotenv
rstcheck
docutils
esbonio
pytz
certifi-linux