Adds the three response headers SecurityHeaders() was missing before 1.0 (#91): Strict-Transport-Security, Content-Security-Policy, and Permissions-Policy. Scope is that one function and its test.
HSTS (max-age=31536000; includeSubDomains) is emitted unconditionally. pixa listens plain HTTP behind a TLS-terminating proxy, but browsers ignore an HSTS header received over plaintext (RFC 6797 section 8.1), so it never lies about the connection, and emitting it here avoids trusting a forwarded-proto header (that is the territory of #94, which also edits this file).
CSP baseline is default-src 'self' with frame-ancestors 'none' as the primary clickjacking control; X-Frame-Options: DENY stays as the legacy fallback. script-src/style-src carry 'unsafe-inline' because the generator template has inline onclick handlers and the bundled Tailwind asset injects a runtime <style> element. The Tailwind bundle contains no eval, so 'unsafe-eval' is not needed. Dropping 'unsafe-inline' requires editing the templates, which is outside this issue's file scope — flagged as follow-up, not done as a drive-by.
Permissions-Policy denies features pixa does not use; clipboard is left unlisted so the generator's copy button keeps its same-origin default.
Verification: built the image and ran the server in debug mode in a container, then loaded the real login and authenticated generator pages under the new CSP. Both render; the only subresource is same-origin tailwind.js; all three headers are present. Container and image were removed.
Judgement call: HSTS is emitted unconditionally rather than gated on forwarded-proto, per the issue plan.
Model: opus-4-8
Adds the three response headers `SecurityHeaders()` was missing before 1.0 (https://git.eeqj.de/sneak/pixa/issues/91): `Strict-Transport-Security`, `Content-Security-Policy`, and `Permissions-Policy`. Scope is that one function and its test.
HSTS (`max-age=31536000; includeSubDomains`) is emitted unconditionally. pixa listens plain HTTP behind a TLS-terminating proxy, but browsers ignore an HSTS header received over plaintext (RFC 6797 section 8.1), so it never lies about the connection, and emitting it here avoids trusting a forwarded-proto header (that is the territory of https://git.eeqj.de/sneak/pixa/issues/94, which also edits this file).
CSP baseline is `default-src 'self'` with `frame-ancestors 'none'` as the primary clickjacking control; `X-Frame-Options: DENY` stays as the legacy fallback. `script-src`/`style-src` carry `'unsafe-inline'` because the generator template has inline `onclick` handlers and the bundled Tailwind asset injects a runtime `<style>` element. The Tailwind bundle contains no `eval`, so `'unsafe-eval'` is not needed. Dropping `'unsafe-inline'` requires editing the templates, which is outside this issue's file scope — flagged as follow-up, not done as a drive-by.
Permissions-Policy denies features pixa does not use; clipboard is left unlisted so the generator's copy button keeps its same-origin default.
Verification: built the image and ran the server in debug mode in a container, then loaded the real login and authenticated generator pages under the new CSP. Both render; the only subresource is same-origin `tailwind.js`; all three headers are present. Container and image were removed.
Judgement call: HSTS is emitted unconditionally rather than gated on forwarded-proto, per the issue plan.
Model: opus-4-8
SecurityHeaders() now also sets Strict-Transport-Security,
Content-Security-Policy, and Permissions-Policy.
HSTS is emitted unconditionally: browsers ignore it over plaintext
(RFC 6797 section 8.1), so it never lies about the connection and no
forwarded-proto header need be trusted.
The CSP baseline is default-src 'self' with frame-ancestors 'none' as
the primary clickjacking control. script-src and style-src carry
'unsafe-inline' because the generator template has inline onclick
handlers and the bundled Tailwind asset injects a runtime <style>
element; removing that need is a template change beyond this issue.
Permissions-Policy denies browser features pixa does not use.
Model: opus-4-8
PASS: the three headers carry the values the definition of done in #91 requires, the policy admits everything the served login and generator pages actually use (the same-origin Tailwind script, the inline handlers, Tailwind's runtime style-element injection, the hidden CSRF field, and the same-origin form posts) while correctly needing no unsafe-eval, the headers apply to image and error responses without affecting them, and the local gate (fmt-check, lint, test in Docker) is green.
Model: opus-4-8
PASS: the three headers carry the values the definition of done in https://git.eeqj.de/sneak/pixa/issues/91 requires, the policy admits everything the served login and generator pages actually use (the same-origin Tailwind script, the inline handlers, Tailwind's runtime style-element injection, the hidden CSRF field, and the same-origin form posts) while correctly needing no unsafe-eval, the headers apply to image and error responses without affecting them, and the local gate (fmt-check, lint, test in Docker) is green.
Model: opus-4-8
clawbot
merged commit b4e5300feb into next2026-09-21 20:43:13 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Adds the three response headers
SecurityHeaders()was missing before 1.0 (#91):Strict-Transport-Security,Content-Security-Policy, andPermissions-Policy. Scope is that one function and its test.HSTS (
max-age=31536000; includeSubDomains) is emitted unconditionally. pixa listens plain HTTP behind a TLS-terminating proxy, but browsers ignore an HSTS header received over plaintext (RFC 6797 section 8.1), so it never lies about the connection, and emitting it here avoids trusting a forwarded-proto header (that is the territory of #94, which also edits this file).CSP baseline is
default-src 'self'withframe-ancestors 'none'as the primary clickjacking control;X-Frame-Options: DENYstays as the legacy fallback.script-src/style-srccarry'unsafe-inline'because the generator template has inlineonclickhandlers and the bundled Tailwind asset injects a runtime<style>element. The Tailwind bundle contains noeval, so'unsafe-eval'is not needed. Dropping'unsafe-inline'requires editing the templates, which is outside this issue's file scope — flagged as follow-up, not done as a drive-by.Permissions-Policy denies features pixa does not use; clipboard is left unlisted so the generator's copy button keeps its same-origin default.
Verification: built the image and ran the server in debug mode in a container, then loaded the real login and authenticated generator pages under the new CSP. Both render; the only subresource is same-origin
tailwind.js; all three headers are present. Container and image were removed.Judgement call: HSTS is emitted unconditionally rather than gated on forwarded-proto, per the issue plan.
Model: opus-4-8
PASS: the three headers carry the values the definition of done in #91 requires, the policy admits everything the served login and generator pages actually use (the same-origin Tailwind script, the inline handlers, Tailwind's runtime style-element injection, the hidden CSRF field, and the same-origin form posts) while correctly needing no unsafe-eval, the headers apply to image and error responses without affecting them, and the local gate (fmt-check, lint, test in Docker) is green.
Model: opus-4-8