chore(config): frente D — ESLint boundaries + Husky + commitlint + gitleaks

Higiene de PR antes da primeira feature de domínio.

- Tags Nx canônicas (scope/type/domain) em todos os 5 projetos, incluindo e2e
- depConstraints ESLint: scope:api|web|shared + type:app|e2e|feature|util|data
- Husky 9 + lint-staged: eslint --max-warnings=0 + prettier --check em pre-commit
- commitlint @conventional: tipo obrigatório, scope enum warn, body ilimitado
- gitleaks via Docker: zero leaks no tree completo; allowlist .agents/,.claude/,tmp/
- tmp/ adicionado ao .gitignore (relatórios de scan locais)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-27 19:52:05 +00:00
parent 29321f54c0
commit fdbf40cd1a
10 changed files with 664 additions and 4 deletions

1
.gitignore vendored
View File

@@ -7,6 +7,7 @@ node_modules
dist
build
out
tmp
.nx
.next
.turbo

32
.gitleaks.toml Normal file
View File

@@ -0,0 +1,32 @@
# Gitleaks — SAR Força de Vendas
# Documentação: https://github.com/gitleaks/gitleaks
title = "SAR gitleaks config"
[extend]
useDefault = true # herda todas as regras padrão
[allowlist]
description = "Arquivos e padrões seguros conhecidos"
paths = [
# Arquivos de exemplo — contêm placeholders, nunca segredos reais
".env.example",
".env.test",
# Lock files gerados pelo pnpm — nunca contêm segredos
"pnpm-lock.yaml",
# Ferramentas de agente (BMad skills, Claude config) — docs/templates, não código de produto
'''.agents/''',
'''.claude/''',
# Arquivos temporários / relatórios de CI gerados localmente
'''tmp/''',
]
regexes = [
# Hashes de commit no design log e docs
'''[0-9a-f]{7,40}''',
# UUIDs canônicos usados em testes (requestId, workspaceId)
'''[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}''',
# Valores placeholder explícitos em .env.example
'''(your-|change-me|placeholder|CHANGE_ME|YOUR_)''',
]

2
.husky/commit-msg Executable file
View File

@@ -0,0 +1,2 @@
#!/usr/bin/env sh
pnpm exec commitlint --edit "$1"

21
.husky/pre-commit Executable file
View File

@@ -0,0 +1,21 @@
#!/usr/bin/env sh
# SAR pre-commit: lint-staged → gitleaks
pnpm exec lint-staged
# Gitleaks — detecta segredos antes de empurrar pro Gitea.
# Roda via Docker para não exigir instalação local.
# Fallback silencioso se Docker não estiver disponível (CI tem o binário nativo).
if command -v docker > /dev/null 2>&1 && docker info > /dev/null 2>&1; then
docker run --rm \
-v "$(pwd)":/path \
-w /path \
zricethezav/gitleaks:latest detect \
--config .gitleaks.toml \
--source . \
--no-git \
--redact \
--exit-code 1
else
echo "[pre-commit] Docker indisponível — gitleaks pulado (rode manualmente antes de push)"
fi

View File

@@ -2,6 +2,7 @@
"name": "api-e2e",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"tags": ["scope:api", "type:e2e", "domain:shared"],
"implicitDependencies": ["api"],
"targets": {
"e2e": {

View File

@@ -3,7 +3,7 @@
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"sourceRoot": "apps/web-e2e/src",
"tags": [],
"tags": ["scope:web", "type:e2e", "domain:shared"],
"implicitDependencies": ["web"],
"// targets": "to see all targets run: nx show project web-e2e --web",
"targets": {}

16
commitlint.config.js Normal file
View File

@@ -0,0 +1,16 @@
// Commitlint — Conventional Commits canon JCS SAR.
// Tipos extras: docs, perf, ci, revert (além dos convencionais).
export default {
extends: ['@commitlint/config-conventional'],
rules: {
// Escopo opcional mas encorajado (api | web | shared | infra | docs)
'scope-enum': [
1, // warn, não error — novo escopo pode surgir legitimamente
'always',
['api', 'web', 'shared', 'infra', 'docs', 'e2e', 'config'],
],
// Corpo pode ter qualquer comprimento (mensagens longas são bem-vindas)
'body-max-line-length': [0, 'always', Infinity],
'footer-max-line-length': [0, 'always', Infinity],
},
};

View File

@@ -21,10 +21,33 @@ export default [
enforceBuildableLibDependency: true,
allow: ['^.*/eslint(\\.base)?\\.config\\.[cm]?[jt]s$'],
depConstraints: [
// ── scope ────────────────────────────────────────────────────────
// api só usa libs api ou shared; web só usa libs web ou shared
{ sourceTag: 'scope:api', onlyDependOnLibsWithTags: ['scope:api', 'scope:shared'] },
{ sourceTag: 'scope:web', onlyDependOnLibsWithTags: ['scope:web', 'scope:shared'] },
// shared não pode importar código de app-scope
{ sourceTag: 'scope:shared', onlyDependOnLibsWithTags: ['scope:shared'] },
// ── type ─────────────────────────────────────────────────────────
// apps só dependem de libs (feature/util/data), nunca de outro app
{
sourceTag: '*',
onlyDependOnLibsWithTags: ['*'],
sourceTag: 'type:app',
onlyDependOnLibsWithTags: ['type:feature', 'type:util', 'type:data'],
},
// e2e depende do seu app-par e de utils; nunca de outro app
{
sourceTag: 'type:e2e',
onlyDependOnLibsWithTags: ['type:app', 'type:util'],
},
// features dependem de features, utils e dados — não de apps
{
sourceTag: 'type:feature',
onlyDependOnLibsWithTags: ['type:feature', 'type:util', 'type:data'],
},
// utils são folha — não importam features nem apps
{ sourceTag: 'type:util', onlyDependOnLibsWithTags: ['type:util', 'type:data'] },
// data é camada mais baixa — só pode depender de outra camada data
{ sourceTag: 'type:data', onlyDependOnLibsWithTags: ['type:data'] },
],
},
],

View File

@@ -23,9 +23,12 @@
"graph": "nx graph",
"affected": "nx affected",
"format": "prettier --write .",
"format:check": "prettier --check ."
"format:check": "prettier --check .",
"prepare": "husky"
},
"devDependencies": {
"@commitlint/cli": "^21.0.1",
"@commitlint/config-conventional": "^21.0.1",
"@eslint/js": "^9.8.0",
"@nestjs/schematics": "^11.0.0",
"@nestjs/testing": "^11.0.0",
@@ -66,12 +69,14 @@
"eslint-plugin-playwright": "^1.6.2",
"eslint-plugin-react": "7.35.0",
"eslint-plugin-react-hooks": "5.0.0",
"husky": "^9.1.7",
"jest": "~30.3.0",
"jest-environment-node": "~30.3.0",
"jest-util": "~30.3.0",
"jiti": "2.4.2",
"jsdom": "~22.1.0",
"jsonc-eslint-parser": "^2.1.0",
"lint-staged": "^17.0.5",
"nx": "^22.7.4",
"prettier": "^3.8.3",
"ts-jest": "^29.4.0",
@@ -82,6 +87,10 @@
"vitest": "~4.1.0",
"webpack-cli": "^5.1.4"
},
"lint-staged": {
"*.{ts,tsx,js,jsx,mts,mjs,cts,cjs}": "eslint --max-warnings=0",
"*.{ts,tsx,js,jsx,mts,mjs,cts,cjs,json,md,yaml,yml,css}": "prettier --check"
},
"dependencies": {
"@nestjs/common": "^11.0.0",
"@nestjs/config": "^4.0.4",

555
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff