Compare commits
3 Commits
main
...
1d4b751316
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d4b751316 | ||
|
|
186b5ae199 | ||
|
|
bbc3cbae4e |
@@ -1,9 +1,9 @@
|
||||
name: Release Build (dev → main)
|
||||
name: Release Build (ci → main)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- ci
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
@@ -16,29 +16,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout (volle History)
|
||||
- name: Checkout ci (Integration)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
repository-url: https://git.hexahost.dev/smueller/HexaHost-Frontend
|
||||
ref: dev
|
||||
|
||||
- name: Merge dev in CI-Workspace (Basis main)
|
||||
env:
|
||||
GITEA_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
git config user.name "gitea-actions"
|
||||
git config user.email "actions@local"
|
||||
git remote set-url origin "https://oauth2:${GITEA_TOKEN}@${GITEA_HOST}/${REPO_PATH}.git"
|
||||
git fetch origin main dev
|
||||
|
||||
if git show-ref --verify --quiet refs/remotes/origin/main; then
|
||||
git checkout -B main origin/main
|
||||
git merge origin/dev -X theirs --no-edit -m "ci: merge dev for release build"
|
||||
else
|
||||
echo "main branch missing, initializing from dev"
|
||||
git checkout -B main origin/dev
|
||||
fi
|
||||
ref: ci
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
@@ -60,10 +43,20 @@ jobs:
|
||||
git config user.name "gitea-actions"
|
||||
git config user.email "actions@local"
|
||||
git remote set-url origin "https://oauth2:${GITEA_TOKEN}@${GITEA_HOST}/${REPO_PATH}.git"
|
||||
git fetch origin main ci
|
||||
|
||||
git add -A
|
||||
if git diff --cached --quiet; then
|
||||
echo "No release changes to publish."
|
||||
exit 0
|
||||
fi
|
||||
git commit -m "chore(release): obfuscate and hash production assets [skip ci]"
|
||||
git push origin main
|
||||
|
||||
TREE=$(git write-tree)
|
||||
MSG="chore(release): obfuscate and hash production assets [skip ci]"
|
||||
if git show-ref --verify --quiet refs/remotes/origin/main; then
|
||||
PARENT=$(git rev-parse origin/main)
|
||||
COMMIT=$(git commit-tree "$TREE" -p "$PARENT" -m "$MSG")
|
||||
else
|
||||
COMMIT=$(git commit-tree "$TREE" -m "$MSG")
|
||||
fi
|
||||
git push origin "${COMMIT}:refs/heads/main"
|
||||
|
||||
29
.githooks/commit-msg
Normal file
29
.githooks/commit-msg
Normal file
@@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
# Validiert Commit-Messages nach Conventional Commits
|
||||
# https://www.conventionalcommits.org/
|
||||
|
||||
commit_msg_file="$1"
|
||||
|
||||
first_line=$(sed '/^#/d;/^$/d' "$commit_msg_file" | head -n 1)
|
||||
|
||||
# Merge/Revert von Git erlauben
|
||||
case "$first_line" in
|
||||
Merge\ *|Revert\ *)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
pattern='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore)(\([a-z0-9._-]+\))?!?: .+'
|
||||
|
||||
if ! printf '%s\n' "$first_line" | grep -qE "$pattern"; then
|
||||
echo >&2 "❌ Commit-Message entspricht nicht Conventional Commits."
|
||||
echo >&2 ""
|
||||
echo >&2 " Format: type(scope): description"
|
||||
echo >&2 " Beispiel: feat(products): hide vpc in navigation"
|
||||
echo >&2 ""
|
||||
echo >&2 " Erlaubte types: feat, fix, docs, style, refactor, perf, test, build, ci, chore"
|
||||
echo >&2 " Überspringen: git commit --no-verify"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
39
.github/workflows/obfuscate-main.yml
vendored
39
.github/workflows/obfuscate-main.yml
vendored
@@ -1,10 +1,10 @@
|
||||
# Hinweis: Gitea nutzt .gitea/workflows/obfuscate-main.yml (identischer Ablauf).
|
||||
name: Release Build (dev → main)
|
||||
name: Release Build (ci → main)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- ci
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
@@ -17,29 +17,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout (volle History)
|
||||
- name: Checkout ci (Integration)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
repository-url: https://git.hexahost.dev/smueller/HexaHost-Frontend
|
||||
ref: dev
|
||||
|
||||
- name: Merge dev in CI-Workspace (Basis main)
|
||||
env:
|
||||
GITEA_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
git config user.name "gitea-actions"
|
||||
git config user.email "actions@local"
|
||||
git remote set-url origin "https://oauth2:${GITEA_TOKEN}@${GITEA_HOST}/${REPO_PATH}.git"
|
||||
git fetch origin main dev
|
||||
|
||||
if git show-ref --verify --quiet refs/remotes/origin/main; then
|
||||
git checkout -B main origin/main
|
||||
git merge origin/dev -X theirs --no-edit -m "ci: merge dev for release build"
|
||||
else
|
||||
echo "main branch missing, initializing from dev"
|
||||
git checkout -B main origin/dev
|
||||
fi
|
||||
ref: ci
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
@@ -61,10 +44,20 @@ jobs:
|
||||
git config user.name "gitea-actions"
|
||||
git config user.email "actions@local"
|
||||
git remote set-url origin "https://oauth2:${GITEA_TOKEN}@${GITEA_HOST}/${REPO_PATH}.git"
|
||||
git fetch origin main ci
|
||||
|
||||
git add -A
|
||||
if git diff --cached --quiet; then
|
||||
echo "No release changes to publish."
|
||||
exit 0
|
||||
fi
|
||||
git commit -m "chore(release): obfuscate and hash production assets [skip ci]"
|
||||
git push origin main
|
||||
|
||||
TREE=$(git write-tree)
|
||||
MSG="chore(release): obfuscate and hash production assets [skip ci]"
|
||||
if git show-ref --verify --quiet refs/remotes/origin/main; then
|
||||
PARENT=$(git rev-parse origin/main)
|
||||
COMMIT=$(git commit-tree "$TREE" -p "$PARENT" -m "$MSG")
|
||||
else
|
||||
COMMIT=$(git commit-tree "$TREE" -m "$MSG")
|
||||
fi
|
||||
git push origin "${COMMIT}:refs/heads/main"
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,6 +13,7 @@ build/
|
||||
# Environment variables
|
||||
.env
|
||||
.cursorrules
|
||||
.cursor/
|
||||
.cursorrules.txt
|
||||
.env.local
|
||||
.env.development.local
|
||||
|
||||
16
.gitmessage
Normal file
16
.gitmessage
Normal file
@@ -0,0 +1,16 @@
|
||||
# Conventional Commits – nur die erste nicht-kommentierte Zeile wird verwendet
|
||||
# Format: type(scope): description
|
||||
#
|
||||
# feat Neues Feature
|
||||
# fix Bugfix
|
||||
# docs Dokumentation
|
||||
# style Formatierung (keine Logik)
|
||||
# refactor Umbau ohne Feature/Fix
|
||||
# perf Performance
|
||||
# test Tests
|
||||
# build Build / Dependencies
|
||||
# ci CI/CD
|
||||
# chore Sonstiges
|
||||
#
|
||||
# Beispiel (diese Zeile anpassen und Kommentare löschen oder stehen lassen):
|
||||
# feat(products): hide vpc and vps in navigation
|
||||
31
README.md
31
README.md
@@ -169,16 +169,33 @@ Für den Produktivbetrieb `public/` als Webroot konfigurieren.
|
||||
| Branch | Zweck |
|
||||
|--------|--------|
|
||||
| **`dev`** | Entwicklung (lesbarer Code, Kommentare) |
|
||||
| **`main`** | Release/Produktion (obfuskiert, gehashte Assets) |
|
||||
| **`ci`** | Integration (du mergst `dev` hierher) |
|
||||
| **`main`** | Release/Produktion (obfuskiert, gehashte Assets — nur per Pipeline) |
|
||||
|
||||
**Workflow:** Nur auf `dev` entwickeln und pushen — **nicht** `dev` manuell nach `main` mergen.
|
||||
**Ablauf: `dev` → `ci` → `main`**
|
||||
|
||||
Bei jedem Push auf `dev` startet `.gitea/workflows/obfuscate-main.yml`:
|
||||
1. Auf **`dev`** entwickeln und pushen
|
||||
2. **`dev` nach `ci` mergen** (manuell, z. B. in Gitea oder lokal)
|
||||
3. **`ci` pushen** → startet `.gitea/workflows/obfuscate-main.yml`
|
||||
4. Pipeline obfuskiert im Runner-Workspace und publiziert nach **`main`**
|
||||
|
||||
1. Checkout in temporärem Runner-Workspace
|
||||
2. `dev` in CI mit `main` mergen (`-X theirs`, dev-Inhalte bei Konflikten)
|
||||
3. Obfuscation-Build (`scripts/obfuscate_release.py --hash-assets`)
|
||||
4. Ergebnis nach `main` pushen (Bot-Commit mit `[skip ci]`)
|
||||
```powershell
|
||||
# Nach fertigen Änderungen auf dev:
|
||||
git checkout ci
|
||||
git pull origin ci
|
||||
git merge dev
|
||||
git push origin ci
|
||||
```
|
||||
|
||||
Bei jedem Push auf **`ci`**:
|
||||
|
||||
1. Checkout von `ci` im temporären Runner-Workspace
|
||||
2. Obfuscation-Build (`scripts/obfuscate_release.py --hash-assets`)
|
||||
3. Ergebnis nach `main` pushen (Bot-Commit mit `[skip ci]`)
|
||||
|
||||
**Nicht** `dev` oder `ci` direkt nach `main` mergen. Der Branch **`ci` bleibt lesbar** — Obfuscation wird nur nach `main` publiziert.
|
||||
|
||||
`ci`-Branch einmalig anlegen (falls noch nicht vorhanden): `git checkout -b ci dev && git push -u origin ci`
|
||||
|
||||
Der Build führt aus:
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ define('SMTP_TO_EMAIL', 'info@hexahost.de'); // Empfänger-E-Mail für Kon
|
||||
// Sicherheitseinstellungen
|
||||
define('ENABLE_CSRF_PROTECTION', true); // CSRF-Schutz aktivieren
|
||||
define('ENABLE_RATE_LIMITING', true); // Rate-Limiting aktivieren
|
||||
define('MAX_REQUESTS_PER_HOUR', 10); // Max. Anfragen pro Stunde
|
||||
define('MAX_REQUESTS_PER_HOUR', 5); // Max. Anfragen pro Stunde
|
||||
|
||||
// Spam-Schutz Einstellungen
|
||||
define('ENABLE_SPAM_PROTECTION', true); // Spam-Schutz aktivieren
|
||||
|
||||
@@ -443,10 +443,43 @@ $PRODUCTS['webhosting'] = [
|
||||
],
|
||||
];
|
||||
|
||||
// Sichtbarkeit in Navigation, Footer und auf der Startseite (Seiten bleiben per URL erreichbar)
|
||||
$PRODUCT_VISIBILITY = [
|
||||
'vpc' => false,
|
||||
'vps' => false,
|
||||
'mail-gateway' => false,
|
||||
'webhosting' => true,
|
||||
];
|
||||
|
||||
// ============================================================================
|
||||
// HILFSFUNKTIONEN
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Prüft, ob eine Produktkategorie in der Navigation angezeigt wird
|
||||
*/
|
||||
function isProductVisible(string $productId): bool {
|
||||
global $PRODUCT_VISIBILITY;
|
||||
return $PRODUCT_VISIBILITY[$productId] ?? true;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML hidden-Attribut für ausgeblendete Produktkategorien
|
||||
*/
|
||||
function productHiddenAttr(string $productId): string {
|
||||
return isProductVisible($productId) ? '' : ' hidden';
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktive Navigationsseiten für sichtbare Produktkategorien
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
function getVisibleProductPageIds(): array {
|
||||
global $PRODUCT_VISIBILITY;
|
||||
return array_keys(array_filter($PRODUCT_VISIBILITY, static fn(bool $visible): bool => $visible));
|
||||
}
|
||||
|
||||
/**
|
||||
* Alle Produkte abrufen
|
||||
*/
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
<div class="footer-section">
|
||||
<h4>Produkte</h4>
|
||||
<ul>
|
||||
<li><a href="/vpc">Virtual Private Container</a></li>
|
||||
<li><a href="/vps">Virtual Private Server</a></li>
|
||||
<li><a href="/mail-gateway">Mail Gateway</a></li>
|
||||
<li><a href="/webhosting">Webhosting</a></li>
|
||||
<li<?php echo productHiddenAttr('vpc'); ?>><a href="/vpc">Virtual Private Container</a></li>
|
||||
<li<?php echo productHiddenAttr('vps'); ?>><a href="/vps">Virtual Private Server</a></li>
|
||||
<li<?php echo productHiddenAttr('mail-gateway'); ?>><a href="/mail-gateway">Mail Gateway</a></li>
|
||||
<li<?php echo productHiddenAttr('webhosting'); ?>><a href="/webhosting">Webhosting</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-section">
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* Helper functions for HexaHost.de
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../config/products-config.php';
|
||||
|
||||
// Sichere Session-Konfiguration
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
// Session-Cookie-Sicherheit
|
||||
|
||||
@@ -59,12 +59,12 @@
|
||||
<ul class="nav-menu">
|
||||
<li><a href="/" class="nav-link <?php echo ($current_page === 'home') ? 'active' : ''; ?>">Home</a></li>
|
||||
<li class="nav-dropdown">
|
||||
<a href="#" class="nav-link <?php echo (in_array($current_page, ['vpc', 'vps', 'mail-gateway', 'webhosting'])) ? 'active' : ''; ?>">Produkte</a>
|
||||
<a href="#" class="nav-link <?php echo (in_array($current_page, getVisibleProductPageIds(), true)) ? 'active' : ''; ?>">Produkte</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/vpc" class="<?php echo ($current_page === 'vpc') ? 'active' : ''; ?>">Virtual Private Container</a></li>
|
||||
<li><a href="/vps" class="<?php echo ($current_page === 'vps') ? 'active' : ''; ?>">Virtual Private Server</a></li>
|
||||
<li><a href="/mail-gateway" class="<?php echo ($current_page === 'mail-gateway') ? 'active' : ''; ?>">Mail Gateway</a></li>
|
||||
<li><a href="/webhosting" class="<?php echo ($current_page === 'webhosting') ? 'active' : ''; ?>">Webhosting</a></li>
|
||||
<li<?php echo productHiddenAttr('vpc'); ?>><a href="/vpc" class="<?php echo ($current_page === 'vpc') ? 'active' : ''; ?>">Virtual Private Container</a></li>
|
||||
<li<?php echo productHiddenAttr('vps'); ?>><a href="/vps" class="<?php echo ($current_page === 'vps') ? 'active' : ''; ?>">Virtual Private Server</a></li>
|
||||
<li<?php echo productHiddenAttr('mail-gateway'); ?>><a href="/mail-gateway" class="<?php echo ($current_page === 'mail-gateway') ? 'active' : ''; ?>">Mail Gateway</a></li>
|
||||
<li<?php echo productHiddenAttr('webhosting'); ?>><a href="/webhosting" class="<?php echo ($current_page === 'webhosting') ? 'active' : ''; ?>">Webhosting</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="/it-dienstleistungen" class="nav-link <?php echo ($current_page === 'it-dienstleistungen') ? 'active' : ''; ?>">IT-Dienstleistungen</a></li>
|
||||
|
||||
@@ -54,7 +54,7 @@ includeHeader($page_title, $page_description, $current_page);
|
||||
</p>
|
||||
</div>
|
||||
<div class="products-grid">
|
||||
<div class="product-card glass-card">
|
||||
<div class="product-card glass-card"<?php echo productHiddenAttr('vpc'); ?>>
|
||||
<div class="product-icon">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M4 7V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v3"/>
|
||||
@@ -74,7 +74,7 @@ includeHeader($page_title, $page_description, $current_page);
|
||||
</ul>
|
||||
<a href="/vpc" class="btn btn-primary">Mehr erfahren</a>
|
||||
</div>
|
||||
<div class="product-card glass-card">
|
||||
<div class="product-card glass-card"<?php echo productHiddenAttr('vps'); ?>>
|
||||
<div class="product-icon">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
|
||||
@@ -92,7 +92,7 @@ includeHeader($page_title, $page_description, $current_page);
|
||||
</ul>
|
||||
<a href="/vps" class="btn btn-primary">Mehr erfahren</a>
|
||||
</div>
|
||||
<div class="product-card glass-card">
|
||||
<div class="product-card glass-card"<?php echo productHiddenAttr('mail-gateway'); ?>>
|
||||
<div class="product-icon">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
|
||||
|
||||
17
scripts/setup-git-hooks.ps1
Normal file
17
scripts/setup-git-hooks.ps1
Normal file
@@ -0,0 +1,17 @@
|
||||
# Einmal pro Clone ausführen: Commit-Template + Conventional-Commits-Hook aktivieren
|
||||
$ErrorActionPreference = "Stop"
|
||||
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..")
|
||||
|
||||
Push-Location $repoRoot
|
||||
try {
|
||||
git config --local commit.template .gitmessage
|
||||
git config --local core.hooksPath .githooks
|
||||
|
||||
Write-Host "Git Hooks aktiv:" -ForegroundColor Green
|
||||
Write-Host " commit.template = .gitmessage"
|
||||
Write-Host " core.hooksPath = .githooks"
|
||||
Write-Host ""
|
||||
Write-Host "Commit-Format: feat(scope): beschreibung"
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
Reference in New Issue
Block a user