Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .Nova/devops.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,13 @@
- **Signal**: Performance logs (redundant GitHub API calls) and Security best practices (missing HSTS/X-Frame-Options).
- **Metric**: Zero security regressions, reduced GitHub API dependency for repeat visitors.
- **Abort Triggers**: None encountered.

## 2026-06-09 - Global Infrastructure Hardening & Asset Optimization

- **Optimization**: Global Security Headers & Immutable Asset Caching.
- **Signal**: Security best practices (Defense in Depth) and Performance metrics (LCP/Bandwidth optimization).
- **Implementation**:
- Hardened `src/pages/api/chat.ts` with `Referrer-Policy` and `Permissions-Policy`.
- Established `public/_headers` for Cloudflare Pages to enforce site-wide security and aggressive caching for `/_astro/*` assets.
- **Metric**: Zero security regressions, optimized cache hit potential for fingerprinted assets.
- **Abort Triggers**: None encountered.
9 changes: 9 additions & 0 deletions public/_headers
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: accelerometer=(), camera=(), geolocation=(), microphone=()
Comment on lines +1 to +6

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check for inline scripts/styles in Astro components and HTML that might conflict with strict CSP

echo "=== Checking for inline script tags ==="
rg -n "<script(?!\\s+src=)" --type=astro --type=html -g '!node_modules' -g '!dist' -C2

echo -e "\n=== Checking for inline style attributes ==="
rg -n "\\sstyle=" --type=astro --type=html -g '!node_modules' -g '!dist' -C1

echo -e "\n=== Checking for inline event handlers ==="
rg -n "\\son[a-z]+=" --type=astro --type=html -g '!node_modules' -g '!dist' -C1

Repository: alehar9320/astro-cloudflare-personal-website

Length of output: 525


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Search for existing Content-Security-Policy in repo ==="
rg -n "Content-Security-Policy" -S . || true

echo
echo "=== Inspect public/_headers (first 50 lines) ==="
if [ -f public/_headers ]; then
  nl -ba public/_headers | head -n 50
else
  echo "Missing: public/_headers"
fi

echo
echo "=== Inspect src/pages/api/chat.ts headers block (best-effort) ==="
if [ -f src/pages/api/chat.ts ]; then
  rg -n "Content-Security-Policy|setHeader|headers" -S src/pages/api/chat.ts || true
  nl -ba src/pages/api/chat.ts | head -n 220
else
  echo "Missing: src/pages/api/chat.ts"
fi

echo
echo "=== Checking for inline script tags (no src) in .astro/.html ==="
# Use --pcre2 for lookahead regex
rg --pcre2 -n "<script(?!\\s+src=)[^>]*>" -g'*.astro' -g'*.html' -g'!**/node_modules/**' -g'!**/dist/**' -C1 . || true

echo
echo "=== Checking for inline style attributes (style=) in .astro/.html ==="
rg -n "\\sstyle=" -g'*.astro' -g'*.html' -g'!**/node_modules/**' -g'!**/dist/**' -C1 . || true

echo
echo "=== Checking for inline event handlers (on*) in .astro/.html ==="
rg -n "\\son[a-z]+=" -g'*.astro' -g'!**/node_modules/**' -g'!**/dist/**' -g'*.astro' -g'*.html' -C1 . || true

Repository: alehar9320/astro-cloudflare-personal-website

Length of output: 676


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Search for existing Content-Security-Policy in repo ==="
rg -n "Content-Security-Policy" -S . || true

echo
echo "=== public/_headers (show entire file) ==="
if [ -f public/_headers ]; then
  echo "--- public/_headers ---"
  cat -n public/_headers
else
  echo "Missing: public/_headers"
fi

echo
echo "=== Inspect src/pages/api/chat.ts for CSP and header setup ==="
if [ -f src/pages/api/chat.ts ]; then
  echo "--- Relevant lines (CSP + header handling) ---"
  rg -n "Content-Security-Policy|setHeader|headers" -S src/pages/api/chat.ts || true
  echo
  echo "--- First 160 lines ---"
  head -n 160 src/pages/api/chat.ts | cat -n
else
  echo "Missing: src/pages/api/chat.ts"
fi

echo
echo "=== Checking for inline script tags (no src) in .astro/.html ==="
rg --pcre2 -n "<script(?!\\s+src=)[^>]*>" -g'*.astro' -g'*.html' -g'!**/node_modules/**' -g'!**/dist/**' -C1 . || true

echo
echo "=== Checking for inline style attributes (style=) in .astro/.html ==="
rg -n "\\sstyle=" -g'*.astro' -g'*.html' -g'!**/node_modules/**' -g'!**/dist/**' -C1 . || true

echo
echo "=== Checking for inline event handlers (on*) in .astro/.html ==="
rg -n "\\son[a-z]+=" -g'*.astro' -g'*.html' -g'!**/node_modules/**' -g'!**/dist/**' -C1 . || true

Repository: alehar9320/astro-cloudflare-personal-website

Length of output: 10600


Document CSP omission (or implement nonce/hash-based CSP) because inline scripts/styles exist

public/_headers currently omits Content-Security-Policy; CSP is only set on the chat API responses (src/pages/api/chat.ts).

Repo pages/layouts contain multiple inline <script> blocks (e.g., src/layouts/BaseLayout.astro, various src/pages/*.astro using script is:inline / <script>...</script>) and inline style="..." usage (e.g., src/pages/experimental/manifesto.astro), so a strict site-wide CSP would break unless you add nonces/hashes or refactor inline code.

Either document that CSP is intentionally omitted for compatibility, or add a CSP to public/_headers using nonces/hashes (and refactor where needed) before tightening defaults.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@public/_headers` around lines 1 - 6, public/_headers lacks a site-wide
Content-Security-Policy while the codebase contains inline scripts/styles (e.g.,
src/layouts/BaseLayout.astro and pages using "script is:inline" and inline style
attributes), so either document the omission or implement a nonce/hash-based CSP
and refactor inline code: choose one—(A) add a clear comment in public/_headers
that CSP is intentionally omitted for compatibility with inline scripts and list
files affected (BaseLayout.astro, src/pages/*.astro,
src/pages/experimental/manifesto.astro) so reviewers know this is deliberate, or
(B) add a CSP entry in public/_headers and refactor to support it by generating
nonces server-side (aligning with src/pages/api/chat.ts pattern), inject the
nonce into BaseLayout.astro and all inline <script> tags as nonce attributes (or
replace inline scripts/styles with external files and/or compute and use sha256
hashes), and ensure server responses set the same nonce/header for pages and API
endpoints that serve HTML.


/_astro/*
Cache-Control: public, max-age=31536000, immutable
4 changes: 4 additions & 0 deletions src/pages/api/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const jsonHeaders = {
'X-Frame-Options': 'DENY',
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'Content-Security-Policy': "default-src 'none'; frame-ancestors 'none';",
'Referrer-Policy': 'strict-origin-when-cross-origin',
'Permissions-Policy': 'accelerometer=(), camera=(), geolocation=(), microphone=()',
} as const;

export const prerender = false;
Expand Down Expand Up @@ -106,6 +108,8 @@ Keep your responses brief, typically 2-3 sentences.`;
'X-Frame-Options': 'DENY',
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'Content-Security-Policy': "default-src 'none'; frame-ancestors 'none';",
'Referrer-Policy': 'strict-origin-when-cross-origin',
'Permissions-Policy': 'accelerometer=(), camera=(), geolocation=(), microphone=()',
},
});
} catch (error: unknown) {
Expand Down
Loading