feat/initial-build #1

Merged
hsiegeln merged 32 commits from feat/initial-build into main 2026-04-24 17:56:10 +02:00
5 changed files with 17 additions and 4 deletions
Showing only changes of commit d98d73b14a - Show all commits

View File

@@ -31,6 +31,14 @@ jobs:
- name: Build site
run: npm run build
- name: Guard — no TBD markers may ship in built HTML
run: |
if grep -rl 'TBD:' dist 2>/dev/null | grep -E '\.(html|svg)$'; then
echo "Built output contains unfilled <TBD:...> markers."
echo "Fill in imprint.astro and privacy.astro operator fields before merging to main."
exit 1
fi
- name: Validate HTML
run: npm run lint:html
@@ -80,6 +88,11 @@ jobs:
SFTP_HOST: ${{ secrets.SFTP_HOST }}
SFTP_PATH: ${{ secrets.SFTP_PATH }}
run: |
# Fail loudly if any secret is missing — otherwise rsync --delete
# could be directed at the SSH user's home root.
: "${SFTP_USER:?SFTP_USER secret must be set}"
: "${SFTP_HOST:?SFTP_HOST secret must be set}"
: "${SFTP_PATH:?SFTP_PATH secret must be set}"
rsync -avz --delete \
-e "ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes -o UserKnownHostsFile=~/.ssh/known_hosts" \
dist/ "$SFTP_USER@$SFTP_HOST:$SFTP_PATH/"

View File

@@ -8,7 +8,7 @@ module.exports = {
'http://localhost/imprint/index.html',
'http://localhost/privacy/index.html',
],
numberOfRuns: 1,
numberOfRuns: 3,
settings: {
preset: 'desktop',
},

View File

@@ -1,4 +1,2 @@
User-agent: *
Allow: /
Sitemap: https://www.cameleer.io/sitemap-index.xml

View File

@@ -4,6 +4,8 @@ interface Tile {
capability: string;
}
// tile.capability is a compile-time constant defined below — never feed
// user-supplied or CMS content into set:html further down (XSS risk).
const tiles: Tile[] = [
{
outcome: 'Cut debugging time in half.',

View File

@@ -26,13 +26,13 @@ export function buildSecurityHeaders(): Record<string, string> {
"object-src 'none'",
].join('; ');
// Must match .htaccess and the Cloudflare Transform Rule in OPERATOR-CHECKLIST.md.
const permissionsPolicy = [
'geolocation=()',
'microphone=()',
'camera=()',
'payment=()',
'usb=()',
'fullscreen=(self)',
].join(', ');
return {