carlos@cesaints: ~/projects/this-site.md — zsh

Comando: cat projects/this-site.md

projects/this-site.md · 1,5 KB

Este site

Um portfólio que funciona como uma sessão de terminal: cada página responde a um comando, e os comandos seguintes são links, então qualquer pessoa navega clicando. Quem prefere digitar tem um terminal de verdade e uma paleta de comandos, e o conteúdo inteiro se lê sem JavaScript. O próprio site é a evidência: o HTML, os headers e os comandos se conferem no navegador.

Papel
Concepção, arquitetura, desenvolvimento e conteúdo
Período
set/2026 – hoje
O que eu fiz

Eu: Conceito, arquitetura, regras de segurança e de privacidade, conteúdo e cada decisão de design, do sistema de arquivos virtual à paleta de cores.

Diagrama

Uma fonte de conteúdo para as páginas, o terminal e a paleta

O conteúdo tipado é a única fonte. Dele saem as páginas HTML estáticas, que se leem sem JavaScript, o sistema de arquivos virtual com a saída dos comandos, em JSON, e as ações da paleta de comandos. O terminal roda um shell próprio sobre esses dados e desenha a saída em HTML semântico. O formulário de contato, uma das páginas, envia para a única função no servidor, que manda o e-mail pelo Resend.

Contexto e problema

Meu portfólio anterior só mostrava o conteúdo com JavaScript e não enviava headers de segurança. Para quem quer trabalhar com segurança, o próprio site é a primeira coisa que alguém vai testar.

Este site parte de outra premissa: ele é o meu ambiente de trabalho, uma janela de terminal, e cada página é a saída de um comando. Quem não usa terminal não precisa digitar nada: os comandos seguintes aparecem no fim de cada página e são links.

Arquitetura

  • Uma fonte de conteúdo. O conteúdo tipado gera as páginas, o sistema de arquivos virtual, a saída dos comandos e as ações da paleta. Um teste confere que cada arquivo tem página e comando.
  • Um shell de verdade por baixo. Comandos com opções no padrão GNU, mensagens de erro com o texto e o código de saída reais do zsh e do coreutils, manual gerado a partir da definição de cada comando e testes de contrato que rodam cada exemplo.
  • Chuva de código feita de dados reais. O hash do build, os nomes dos comandos e os caminhos dos arquivos. Fica fora da janela de leitura, tem botão de pausa e começa desligada para quem pede menos movimento.
  • Contato sem terceiros no navegador. Formulário que funciona sem JavaScript, com validação e proteção contra spam no servidor.

O que eu faria diferente

Escreveria a guarda de privacidade antes de ler qualquer repositório, e não logo depois. Foi o primeiro controle que eu quis ter e o último que pensei em construir.

Restrições

  • Todo o conteúdo acessível sem digitar comandos e sem JavaScript.
  • Uma única fonte de conteúdo para as páginas, o sistema de arquivos virtual e os comandos.
  • Nenhum nome de cliente, empresa ou repositório privado em arquivo versionado sem autorização.
  • WCAG 2.2 AA, com teclado e leitor de tela.
  • Deploy só com o CI inteiro verde.

Decisões

Astro estático em vez de um framework de aplicação

Contexto
O conteúdo é estático e precisa ser lido sem JavaScript; o terminal, a paleta de comandos e a chuva são camadas por cima dele.
Escolha
Astro gerando HTML estático, com uma única função no servidor (o formulário de contato).
Ganhos
  • Nenhum framework no navegador para ler o conteúdo.
  • CSP por hash em todas as páginas.
Custos
  • Recursos interativos exigem ilhas separadas e um cuidado extra com a CSP.

Comandos de terminal como dados, não como texto solto

Contexto
Queria que a metáfora de terminal fosse de verdade: comandos com opções, erros e códigos de saída reais, e não uma animação de digitação.
Escolha
Um núcleo de shell próprio (tokenizador no padrão POSIX, parser de opções no padrão GNU, mensagens do zsh e do coreutils) que gera saídas estruturadas, renderizadas como HTML semântico.
Ganhos
  • Acessível e indexável; cada comando tem manual e teste de contrato.
Custos
  • Mais código para manter do que um terminal de enfeite.

Guarda de privacidade com a lista de bloqueio fora do repositório

Contexto
O conteúdo veio da leitura de repositórios privados; nomes reais não podem vazar num commit.
Escolha
Hook de pre-commit e job de CI comparam os arquivos versionados com uma lista que fica fora do repositório (local e como secret do CI). O log aponta só o índice do termo, nunca o termo.
Ganhos
  • O repositório pode ser público sem expor os nomes que a guarda protege.
Custos
  • Depende de manter a lista atualizada.

Stack e por quê

Astro 7 e Preact
HTML estático por padrão e ilhas pequenas para o que é interativo.
TypeScript estrito
Contratos entre conteúdo, sistema de arquivos virtual e comandos.
Vitest e Playwright
Testes unitários do núcleo do shell, dos comandos, da sessão, do contato e da chuva; no navegador, cada página com e sem JavaScript, com checagem de acessibilidade.
Resend
Envio do formulário de contato validado no servidor.
Vercel
Hospedagem estática com uma função; deploy só pelo CI.

Resultados

  • Todo o conteúdo, inclusive os estudos de caso, o CV e o diário de segurança, se lê e se navega sem JavaScript.

    link públicoO próprio site, com o JavaScript desligado(set/2026)
  • Cada cor de texto dos dois temas é conferida contra cada fundo da janela por um teste que lê as cores do próprio código, e todos os pares passam no contraste AA da WCAG.

    link públicoComo este site foi feito(set/2026)

Ângulo de segurança

Superfície de ataque

  • Formulário de contato (a única função no servidor).
  • Arquivos JSON estáticos com os dados dos comandos.

Controles implementados

  • CSP por hash, frame-ancestors 'none' e headers de segurança.
  • Nenhum HTML montado a partir de string, com regra de lint que reprova innerHTML e similares.
  • Validação no servidor, honeypot, token de tempo, rate limit e orçamento diário no contato.
  • Segredos só nas variáveis de ambiente do host; varredura de segredos no CI.

O que eu testaria hoje

  • XSS por parâmetros de URL e pelo formulário.
  • Abuso do formulário para esgotar a cota diária de e-mails.
  • Clickjacking e contornos de CSP.

Evidências