diff --git a/.claude/security-patterns.json b/.claude/security-patterns.json new file mode 100644 index 0000000..7d61a62 --- /dev/null +++ b/.claude/security-patterns.json @@ -0,0 +1,75 @@ +{ + "_doc": "Regras determinísticas da KingPanda para o plugin security-guidance. Formato JSON e não YAML de propósito: o plugin importa PyYAML de forma preguiçosa e, onde ele não estiver instalado, descarta o .yaml em silêncio — só escreve no log de debug. JSON não tem dependência. Contrato lido de hooks/extensibility.py do plugin em 2026-08-24: rule_name e reminder são obrigatórios, precisa de regex ou substrings, teto de 50 regras somando todas as fontes, reminder truncado em 1024 bytes, regex com estrutura ReDoS-prone é recusado. Campos iniciados por _ são ignorados pelo plugin. Não repita as 22 regras embutidas (eval, dangerouslySetInnerHTML, innerHTML, document.write, child_process.exec, os.system, subprocess com shell, pickle, yaml inseguro, XML, TLS desligado, AES-ECB, SRI, e edição em .github/workflows) — elas não podem ser desligadas e repetir gasta o teto. Cada regra declara em _tiers onde ela vale; scripts/sync-repos.sh deriva o arquivo de cada repositório a partir deste, que é a fonte única.", + "patterns": [ + { + "_comentario": "O plugin não traz nenhuma regra de prefixo de chave. Estes são os provedores que esta organização usa de fato.", + "rule_name": "segredo_hardcoded", + "reminder": "Isto tem a forma de uma credencial viva. Chave em código entra no histórico do git e continua lá depois do revert. Mova para variável de ambiente ou secret do repositório, e ROTACIONE a chave — assumir que não vazou porque o PR não foi mesclado é assumir errado.", + "regex": "(sk_live_[A-Za-z0-9]{8}|AKIA[0-9A-Z]{12}|dop_v1_[a-f0-9]{16}|ghp_[A-Za-z0-9]{20}|xoxb-[0-9]{8})", + "_exemplo": { + "casa": { + "caminho": "app/Pay.php", + "trecho": "$key = 'sk_live_4eC39HqLyjWD';" + }, + "nao_casa": { + "caminho": "app/Pay.php", + "trecho": "$key = getenv('STRIPE_SECRET_KEY');" + } + }, + "_tiers": [ + "T0", + "T1", + "T2" + ] + }, + { + "rule_name": "chave_privada_em_arquivo", + "reminder": "Bloco de chave privada em arquivo versionado. Se for a chave de um GitHub App ou de deploy, ela pertence aos secrets da organização, e o que entra no repositório é só o id. Rotacione antes de mesclar.", + "substrings": [ + "-----BEGIN RSA PRIVATE KEY-----", + "-----BEGIN OPENSSH PRIVATE KEY-----", + "-----BEGIN PRIVATE KEY-----" + ], + "_exemplo": { + "casa": { + "caminho": "deploy/key.pem", + "trecho": "-----BEGIN RSA PRIVATE KEY-----" + }, + "nao_casa": { + "caminho": "deploy/key.pub", + "trecho": "ssh-rsa AAAAB3NzaC1yc2E user@host" + } + }, + "_tiers": [ + "T0", + "T1", + "T2" + ] + }, + { + "_comentario": "O built-in github_actions_workflow cobre .github/workflows. Não cobre manifesto de produção.", + "rule_name": "manifesto_de_producao", + "reminder": "Alteração em manifesto de produção muda o que roda no cluster. Confira o que mudou em réplicas, limites de recurso, imagem e secret montado — e confirme que a imagem referenciada é tag imutável ou digest, não latest. Mudança aqui vai por PR revisado; não existe rollback automático de configuração aplicada à mão.", + "regex": "(image:|replicas:|secretKeyRef|resources:|imagePullPolicy)", + "paths": [ + "k8s/prod/**", + "**/k8s/prod/**" + ], + "_exemplo": { + "casa": { + "caminho": "k8s/prod/api.yaml", + "trecho": " image: registry.digitalocean.com/kp/api:latest" + }, + "nao_casa": { + "caminho": "k8s/homolog/api.yaml", + "trecho": " image: registry.digitalocean.com/kp/api:latest" + } + }, + "_tiers": [ + "T0", + "T1", + "T2" + ] + } + ] +} diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..2e94aeb --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,5 @@ +{ + "env": { + "OTEL_RESOURCE_ATTRIBUTES": "org=kingpanda,repo=php-kafka-client,tier=T2,origem=sync-repos" + } +} diff --git a/REVIEW.md b/REVIEW.md new file mode 100644 index 0000000..4588445 --- /dev/null +++ b/REVIEW.md @@ -0,0 +1,51 @@ +# Instruções de revisão — repositório T2 + +## O que é 🔴 Important aqui + +Este repositório é de apoio: ferramenta, documentação ou configuração, sem +caminho direto para produção. A calibração padrão da revisão mira código de +produção e aqui produziria ruído. + +Reserve 🔴 Important para dois casos, e só para eles: + +- **Segredo, token ou credencial no código** +- **Script ou configuração que apaga, sobrescreve ou expõe dado de produção** + +Todo o resto é 🟡 Nit. Se não tiver quase certeza, não reporte. + +## Teto de 🟡 Nit + +No máximo três nits por revisão. Achou mais, diga "mais N itens semelhantes" no +resumo. + +## Não reporte + +- O que o CI já reprova: formatação, lint, erro de tipo, dependência vulnerável + e segredo pego pelo `gitleaks` — o workflow `seguranca.yml` já falha nesses +- Arquivo gerado e arquivo de bloqueio de dependência (`*.lock`, `composer.lock`, + `package-lock.json`, `vendor/`, `node_modules/`) +- Código de teste que viola de propósito uma regra de produção, quando o próprio + teste diz que é isso que está fazendo +- Preferência de estilo sem consequência de comportamento + +## Sempre confira + +- Nenhum segredo entrou no arquivo, nem em exemplo +- Script que escreve em produção diz, no próprio texto, como reverter + +## Barra de evidência + +Afirmação sobre comportamento precisa de citação `arquivo:linha` no código, não +de inferência a partir do nome de uma função. Achado que não passa nessa barra +custa uma ida e volta ao autor e ensina o time a ignorar a revisão. + +## Revisão repetida na mesma PR + +Depois da primeira revisão, não abra nit novo: reporte só 🔴 Important. Uma +correção de uma linha não pode chegar à sétima rodada por causa de estilo. + +## Forma do resumo + +Comece o resumo com uma contagem em uma linha, no formato `2 importantes, 4 +nits`. Quando não houver achado importante, a primeira frase é "nenhum achado +que bloqueie".