fix: Storybook trava num spinner infinito por causa do X-Frame-Options global #74

Merged
jhony75 merged 1 commit from fix/storybook-frame-options into develop 2026-09-17 19:29:01 -03:00
Owner

Sintoma: Storybook abre (sidebar carrega normal), mas a pré-visualização de cada componente fica presa num spinner infinito.

Causa raiz: o Storybook carrega a própria pré-visualização (iframe.html) dentro de um <iframe> na mesma origem -- é assim que o "manager" dele sempre funcionou, não uma integração nova. frontend/nginx.conf define X-Frame-Options: DENY no bloco server (linha 9, pra proteger o app contra clickjacking) e location /storybook/ não tinha add_header próprio, então herdava esse header -- bloqueando o Storybook de se auto-framar.

Confirmado ao vivo em dev-eegqa.jonataslima.xyz: GET /storybook/iframe.html retornava 200, mas o navegador recusava renderizar (net::ERR_BLOCKED_BY_RESPONSE + Refused to display '.../iframe.html' in a frame because it set 'X-Frame-Options' to 'deny' no console).

Fix: location /storybook/ ganhou seus próprios add_header, com SAMEORIGIN em vez de DENY -- permite esse self-frame e continua bloqueando framing por terceiros. Repete os outros 3 headers de segurança porque add_header do nginx não herda do bloco pai quando a location redeclara qualquer um deles (comportamento documentado do nginx, não uma escolha nova).

Verificação: não deu pra rebuildar a imagem localmente (sem Docker rodando neste ambiente) -- a causa raiz foi confirmada inspecionando os headers de resposta reais do deploy de dev via fetch() autenticado no navegador (x-frame-options: deny presente em /storybook/ e /storybook/iframe.html, ausente nas demais rotas do app). Depois do deploy, confirmar abrindo qualquer story -- a pré-visualização deve renderizar em vez de ficar no spinner.

🤖 Generated with Claude Code

**Sintoma**: Storybook abre (sidebar carrega normal), mas a pré-visualização de cada componente fica presa num spinner infinito. **Causa raiz**: o Storybook carrega a própria pré-visualização (`iframe.html`) dentro de um `<iframe>` na mesma origem -- é assim que o "manager" dele sempre funcionou, não uma integração nova. `frontend/nginx.conf` define `X-Frame-Options: DENY` no bloco `server` (linha 9, pra proteger o app contra clickjacking) e `location /storybook/` não tinha `add_header` próprio, então herdava esse header -- bloqueando o Storybook de se auto-framar. Confirmado ao vivo em `dev-eegqa.jonataslima.xyz`: `GET /storybook/iframe.html` retornava `200`, mas o navegador recusava renderizar (`net::ERR_BLOCKED_BY_RESPONSE` + `Refused to display '.../iframe.html' in a frame because it set 'X-Frame-Options' to 'deny'` no console). **Fix**: `location /storybook/` ganhou seus próprios `add_header`, com `SAMEORIGIN` em vez de `DENY` -- permite esse self-frame e continua bloqueando framing por terceiros. Repete os outros 3 headers de segurança porque `add_header` do nginx não herda do bloco pai quando a location redeclara qualquer um deles (comportamento documentado do nginx, não uma escolha nova). **Verificação**: não deu pra rebuildar a imagem localmente (sem Docker rodando neste ambiente) -- a causa raiz foi confirmada inspecionando os headers de resposta reais do deploy de dev via `fetch()` autenticado no navegador (`x-frame-options: deny` presente em `/storybook/` e `/storybook/iframe.html`, ausente nas demais rotas do app). Depois do deploy, confirmar abrindo qualquer story -- a pré-visualização deve renderizar em vez de ficar no spinner. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix: Storybook trava num spinner infinito por causa do X-Frame-Options global
All checks were successful
EEG QA CI / Detectar o que mudou (pull_request) Successful in 10s
EEG QA CI / Backend (pull_request) Has been skipped
EEG QA CI / Frontend (pull_request) Successful in 3m11s
EEG QA CI / Build e publicação de imagens (pull_request) Successful in 2m36s
EEG QA CI / Deploy production (pull_request) Has been skipped
EEG QA CI / Deploy development (pull_request) Has been skipped
de143db3ee
O Storybook carrega a própria pré-visualização (iframe.html) num <iframe> na
mesma origem -- é assim que o "manager" dele sempre funcionou. O
X-Frame-Options: DENY do bloco server (linha 9, protege o app contra
clickjacking) era herdado por location /storybook/ e bloqueava esse
auto-frame (confirmado: GET /storybook/iframe.html retornava 200 mas o
navegador recusava renderizar, ERR_BLOCKED_BY_RESPONSE + "Refused to display
... because it set X-Frame-Options to deny" no console).

location /storybook/ ganhou seus próprios add_header, com SAMEORIGIN em vez
de DENY -- permite esse self-frame e continua bloqueando framing por
terceiros. Repete os outros 3 headers de segurança porque add_header do
nginx não herda do bloco pai quando a location redeclara qualquer um.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
jhony75 merged commit 101751a71a into develop 2026-09-17 19:29:01 -03:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jhony75/eeg-qa!74
No description provided.