@brunosps00/dev-workflow 1.0.6 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -29
- package/bin/dev-workflow.js +6 -0
- package/lib/constants.js +2 -2
- package/lib/init.js +13 -3
- package/lib/install-deps.js +88 -3
- package/lib/migrate-gsd.js +1 -1
- package/lib/post-update.js +153 -0
- package/lib/setup-wsl-browser.js +149 -0
- package/lib/uninstall.js +1 -1
- package/package.json +1 -1
- package/scaffold/en/agent-instructions.md +1 -1
- package/scaffold/en/commands/dw-analyze-project.md +22 -0
- package/scaffold/en/commands/dw-autopilot.md +3 -1
- package/scaffold/en/commands/dw-functional-doc.md +11 -3
- package/scaffold/en/commands/dw-generate-pr.md +2 -2
- package/scaffold/en/commands/dw-help.md +29 -14
- package/scaffold/en/commands/dw-qa.md +1 -1
- package/scaffold/en/commands/dw-redesign-ui.md +2 -2
- package/scaffold/en/commands/dw-review.md +7 -5
- package/scaffold/en/commands/dw-secure-audit.md +72 -15
- package/scaffold/en/commands/dw-update.md +16 -1
- package/scaffold/en/templates/constitution-template.md +8 -3
- package/scaffold/en/templates/functional-doc/playwright.flow.mjs.tpl +17 -0
- package/scaffold/pt-br/agent-instructions.md +1 -1
- package/scaffold/pt-br/commands/dw-analyze-project.md +22 -0
- package/scaffold/pt-br/commands/dw-autopilot.md +3 -1
- package/scaffold/pt-br/commands/dw-functional-doc.md +11 -3
- package/scaffold/pt-br/commands/dw-generate-pr.md +2 -2
- package/scaffold/pt-br/commands/dw-help.md +29 -14
- package/scaffold/pt-br/commands/dw-qa.md +1 -1
- package/scaffold/pt-br/commands/dw-redesign-ui.md +2 -2
- package/scaffold/pt-br/commands/dw-review.md +7 -5
- package/scaffold/pt-br/commands/dw-secure-audit.md +72 -15
- package/scaffold/pt-br/commands/dw-update.md +16 -1
- package/scaffold/pt-br/templates/constitution-template.md +8 -3
- package/scaffold/pt-br/templates/functional-doc/playwright.flow.mjs.tpl +17 -0
- package/scaffold/scripts/cdp-relay/Cargo.toml +16 -0
- package/scaffold/scripts/cdp-relay/src/main.rs +49 -0
- package/scaffold/scripts/functional-doc/generate-dossier.mjs +7 -9
- package/scaffold/scripts/functional-doc/run-playwright-flow.mjs +192 -183
- package/scaffold/scripts/lib/capture-screenshots.mjs +133 -0
- package/scaffold/scripts/lib/resolve-browser.mjs +405 -0
- package/scaffold/scripts/lib/ui-slop-detect.mjs +102 -0
- package/scaffold/skills/dw-testing-discipline/references/playwright-recipes.md +50 -0
- package/scaffold/skills/dw-ui-discipline/SKILL.md +5 -0
- package/scaffold/skills/dw-ui-discipline/references/color-oklch.md +60 -0
- package/scaffold/skills/dw-ui-discipline/references/motion.md +52 -0
- package/scaffold/skills/dw-ui-discipline/references/responsive.md +52 -0
- package/scaffold/skills/dw-ui-discipline/references/type-scale.md +48 -0
- package/scaffold/skills/dw-ui-discipline/references/ux-writing.md +52 -0
- package/scaffold/skills/security-review/SKILL.md +19 -0
- package/scaffold/skills/security-review/references/sast.md +67 -0
- package/scaffold/skills/security-review/references/secrets.md +46 -0
- package/scaffold/en/templates/functional-doc/playwright.spec.ts.tpl +0 -19
- package/scaffold/pt-br/templates/functional-doc/playwright.spec.ts.tpl +0 -19
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
<system_instructions>
|
|
2
|
-
Você é o orquestrador de security audit
|
|
2
|
+
Você é o orquestrador de security audit — o **Security Gate**. Roda OWASP static review + SAST (Semgrep,
|
|
3
|
+
focado no diff do código gerado) + secret scan dedicado (gitleaks) + supply-chain CVE/secret/IaC (Trivy +
|
|
4
|
+
native lockfile audit) + supply-chain compromise detection + outdated check, em uma passada. Hard-gates
|
|
5
|
+
comandos downstream quando há qualquer finding bloqueante.
|
|
3
6
|
|
|
4
|
-
|
|
7
|
+
É **auto-invocado por `/dw-review` e `/dw-generate-pr`** (em TS/Python/C#/Rust), roda como **fase explícita e
|
|
8
|
+
nomeada no `/dw-autopilot`** (após review + QA, antes de commit/PR), e é **executável standalone** a qualquer
|
|
9
|
+
momento. O `/dw-generate-pr` re-enforça o verdict como hard gate final. Os três continuam gating em segurança
|
|
10
|
+
— o comando standalone e a fase nomeada são aditivos, não substituem.
|
|
5
11
|
|
|
6
12
|
## Quando Usar
|
|
7
13
|
- Auto-invocado: `/dw-review` e `/dw-generate-pr` em linguagens suportadas.
|
|
@@ -10,7 +16,7 @@ Auto-invocado por `/dw-review` e `/dw-generate-pr` em projetos TS/Python/C#/Rust
|
|
|
10
16
|
- NÃO use como substituto pra review humano em código auth/payment de alto risco (use skill `security-review` JUNTO com este).
|
|
11
17
|
|
|
12
18
|
## Posição no Pipeline
|
|
13
|
-
**Antecessor:**
|
|
19
|
+
**Antecessor:** `/dw-review` + `/dw-qa` (o Security Gate roda depois deles passarem) | **Sucessor:** `/dw-commit` / `/dw-generate-pr` se APROVADO, ou `/dw-bugfix` pra atacar findings. Também roda standalone a qualquer momento.
|
|
14
20
|
|
|
15
21
|
## Modos
|
|
16
22
|
|
|
@@ -33,10 +39,20 @@ Auto-invocado por `/dw-review` e `/dw-generate-pr` em projetos TS/Python/C#/Rust
|
|
|
33
39
|
|
|
34
40
|
## Dependências Necessárias
|
|
35
41
|
|
|
36
|
-
- **Trivy** —
|
|
42
|
+
- **Trivy** — SCA / secrets / IaC (via `npx @brunosps00/dev-workflow install-deps`).
|
|
43
|
+
- **Semgrep** — camada SAST (opcional mas recomendado). Se ausente, a camada SAST é pulada e anotada.
|
|
44
|
+
- **gitleaks** — secret scan dedicado (opcional mas recomendado). Se ausente, cai pro Trivy secrets.
|
|
37
45
|
- **Context7 MCP** — pra best practices específicas de versão.
|
|
38
46
|
|
|
39
|
-
|
|
47
|
+
Todos os scanners são opcionais individualmente: uma tool ausente degrada aquela camada e é **reportada**
|
|
48
|
+
no summary (o gate nunca quebra por falta de scanner), mas a cobertura faltante fica visível. Instale via
|
|
49
|
+
`npx @brunosps00/dev-workflow install-deps`.
|
|
50
|
+
|
|
51
|
+
## Camadas de Detecção
|
|
52
|
+
|
|
53
|
+
**Foco no diff (código gerado):** camadas que suportam isso focam no diff contra a base do PR
|
|
54
|
+
(`git merge-base HEAD origin/main`), concentrando o gate no código recém-escrito, sem ruído do código
|
|
55
|
+
pré-existente. Um pass periódico `--full` varre a árvore inteira.
|
|
40
56
|
|
|
41
57
|
### Camada 1: OWASP Static Review (via skill `security-review`)
|
|
42
58
|
|
|
@@ -72,6 +88,23 @@ Cruza dependency tree contra:
|
|
|
72
88
|
|
|
73
89
|
Output: `.dw/secure-audit/compromise-findings.md` por pacote afetado: COMPROMISED / suspicious / clean.
|
|
74
90
|
|
|
91
|
+
### Camada 4: SAST — Semgrep (análise semântica do código gerado)
|
|
92
|
+
|
|
93
|
+
Análise estática semântica e determinística do **diff** (`--baseline-commit`), complementando a Camada 1.
|
|
94
|
+
Rulesets fixados: `p/security-audit`, `p/owasp-top-ten`, `p/secrets` (+ packs de linguagem detectados).
|
|
95
|
+
Mapeie Semgrep `ERROR`→HIGH (ou CRITICAL pra CWEs RCE/authn-bypass/SQLi), `WARNING`→MEDIUM, `INFO`→LOW.
|
|
96
|
+
Aplique a disciplina **fp-check** (reachability) antes de um finding bloquear (ver `security-review/references/sast.md`).
|
|
97
|
+
|
|
98
|
+
Output: `.dw/secure-audit/sast-findings.md`. Se `semgrep` ausente: pulado + anotado no summary.
|
|
99
|
+
|
|
100
|
+
### Camada 5: Secret scan dedicado — gitleaks
|
|
101
|
+
|
|
102
|
+
`gitleaks protect --staged` (não-commitado) ou `gitleaks detect --log-opts <base>..HEAD` (branch), `--redact`.
|
|
103
|
+
Autoritativo no diff; complementa Trivy secrets (dedupe por `file:line`). **Qualquer hit = REPROVADO, sem
|
|
104
|
+
exceção de ADR** — secrets são removidos e rotacionados, não justificados. Ver `security-review/references/secrets.md`.
|
|
105
|
+
|
|
106
|
+
Output: `.dw/secure-audit/secret-findings.md`. Se `gitleaks` ausente: cai pro Trivy secrets + anotado.
|
|
107
|
+
|
|
75
108
|
### Plus: outdated check
|
|
76
109
|
|
|
77
110
|
`npm outdated` / `pip list --outdated` / `dotnet list outdated` / `cargo outdated` pra identificar pacotes atrás em minor ou major.
|
|
@@ -84,9 +117,11 @@ Todos os findings são classificados num desses tiers em `.dw/secure-audit/audit
|
|
|
84
117
|
|
|
85
118
|
| Tier | Critério | Bloqueia | Ação Sugerida |
|
|
86
119
|
|------|----------|----------|---------------|
|
|
120
|
+
| **SECRET** | Credencial/chave/token hardcoded (gitleaks ou Trivy), sobrevive ao allowlist | SIM — **sem exceção de ADR** | Remover do código + histórico, rotacionar, mover pra secret store |
|
|
87
121
|
| **COMPROMISED** | Pacote conhecido como malicioso nessa faixa de versão | SIM | Remover imediato / pin pra versão segura |
|
|
88
|
-
| **CRITICAL** | CVE CVSS ≥9.0 OU exploit ativo OU auth bypass | SIM | Update ou
|
|
89
|
-
| **HIGH** | CVE CVSS 7.0–8.9 OU exploitável no contexto
|
|
122
|
+
| **CRITICAL** | CVE CVSS ≥9.0 OU exploit ativo OU auth bypass; OU SAST de CWE alto-impacto (SQLi/RCE/authn-bypass/SSRF/deserialization) alcançável | SIM | Update/substituir ou corrigir em 24h |
|
|
123
|
+
| **HIGH** | CVE CVSS 7.0–8.9 OU exploitável no contexto; OU Semgrep `ERROR` alcançável (fp-check passou) | SIM | Update/substituir ou corrigir em 1 semana |
|
|
124
|
+
| **MEDIUM / LOW** | CVE CVSS <7.0; OU Semgrep `WARNING`/`INFO`; OU finding inalcançável rebaixado pelo fp-check | NÃO (advisory) | Rastrear e corrigir rotineiramente |
|
|
90
125
|
| **OUTDATED-MAJOR** | ≥1 major version atrás (ex: React 17 → 19) | NÃO | Planejar migração próximo trimestre |
|
|
91
126
|
| **OUTDATED-MINOR** | Minor/patch atrás | NÃO | Update rotineiro |
|
|
92
127
|
| **CLEAN** | Sem findings | NÃO | — |
|
|
@@ -94,19 +129,26 @@ Todos os findings são classificados num desses tiers em `.dw/secure-audit/audit
|
|
|
94
129
|
## Hard Gates
|
|
95
130
|
|
|
96
131
|
Verdict é um de:
|
|
97
|
-
- **APROVADO** — sem
|
|
98
|
-
- **REPROVADO** — ≥1
|
|
132
|
+
- **APROVADO** — sem SECRET, COMPROMISED, CRITICAL ou HIGH. Arquivo verdict `.dw/secure-audit/audit-summary.md` status: APROVADO. (MEDIUM/LOW/outdated podem aparecer como advisory.)
|
|
133
|
+
- **REPROVADO** — ≥1 SECRET (sempre), ou ≥1 COMPROMISED/CRITICAL/HIGH sem ADR explícito ou remediação em andamento. Status: REPROVADO.
|
|
134
|
+
|
|
135
|
+
**Limiar Rigoroso:** SECRET e COMPROMISED sempre bloqueiam. CRITICAL/HIGH (CVE ou SAST alcançável) bloqueiam salvo ADR justificando aceitação. MEDIUM/LOW e outdated são advisory. SECRET é o único tier **sem escape via ADR** — rotacione, não justifique.
|
|
99
136
|
|
|
100
137
|
**`/dw-review` e `/dw-generate-pr` enforçam:** se linguagem do projeto é suportada E `.dw/secure-audit/audit-summary.md` mais recente está faltando OU REPROVADO, esses comandos retornam REPROVADO. Sem exceção. Sem flag bypass.
|
|
101
138
|
|
|
102
139
|
## Modo 1: Default (`/dw-secure-audit`)
|
|
103
140
|
|
|
104
141
|
1. **Detectar stack**: checar package.json / requirements.txt / *.csproj / Cargo.toml.
|
|
105
|
-
2. **Rodar todas as
|
|
106
|
-
- OWASP static (via skill `security-review`).
|
|
142
|
+
2. **Rodar todas as camadas de detecção em paralelo** (onde possível):
|
|
143
|
+
- OWASP static (via skill `security-review`) — focado no diff.
|
|
144
|
+
- SAST — Semgrep no diff (`--baseline-commit`).
|
|
145
|
+
- Secret scan dedicado — gitleaks no diff.
|
|
107
146
|
- Trivy + lockfile audit.
|
|
108
147
|
- Supply-chain compromise check.
|
|
109
148
|
3. **Rodar outdated check.**
|
|
149
|
+
**fp-check:** antes de finalizar, rode validação de reachability em cada finding SAST/OWASP bloqueante
|
|
150
|
+
(ver `security-review` SKILL.md); rebaixe os comprovadamente inalcançáveis pra advisory com razão logada.
|
|
151
|
+
Secrets são isentos de rebaixamento.
|
|
110
152
|
4. **Agregar findings** por tier.
|
|
111
153
|
5. **Escrever summary** em `.dw/secure-audit/audit-summary.md`:
|
|
112
154
|
|
|
@@ -118,14 +160,26 @@ Verdict é um de:
|
|
|
118
160
|
## Resumo por Tier
|
|
119
161
|
| Tier | Contagem | Detalhe |
|
|
120
162
|
|------|----------|---------|
|
|
163
|
+
| SECRET | N | <lista> |
|
|
121
164
|
| COMPROMISED | N | <lista> |
|
|
122
165
|
| CRITICAL | N | <lista> |
|
|
123
166
|
| HIGH | N | <lista> |
|
|
167
|
+
| MEDIUM/LOW (advisory) | N | <lista> |
|
|
124
168
|
| OUTDATED-MAJOR | N | <lista> |
|
|
125
169
|
| OUTDATED-MINOR | N | <lista> |
|
|
126
170
|
|
|
171
|
+
## Scanners
|
|
172
|
+
| Camada | Tool | Status |
|
|
173
|
+
|--------|------|--------|
|
|
174
|
+
| OWASP | security-review | rodou |
|
|
175
|
+
| SAST | semgrep | rodou / pulado (não instalado) |
|
|
176
|
+
| Secrets | gitleaks | rodou / fallback trivy (não instalado) |
|
|
177
|
+
| SCA/IaC | trivy | rodou |
|
|
178
|
+
|
|
127
179
|
## Relatórios das camadas
|
|
128
180
|
- OWASP: `owasp-findings.md`
|
|
181
|
+
- SAST: `sast-findings.md`
|
|
182
|
+
- Secrets: `secret-findings.md`
|
|
129
183
|
- Trivy: `trivy-findings.md`
|
|
130
184
|
- Lockfile: `lockfile-findings.md`
|
|
131
185
|
- Compromise: `compromise-findings.md`
|
|
@@ -164,7 +218,7 @@ Pra cada remediação aprovada:
|
|
|
164
218
|
## Modo 4: CI (`/dw-secure-audit --scan-only`)
|
|
165
219
|
|
|
166
220
|
Output mínimo:
|
|
167
|
-
- Roda todas as
|
|
221
|
+
- Roda todas as camadas de detecção.
|
|
168
222
|
- Escreve findings em disco.
|
|
169
223
|
- Exit code 0 se APROVADO, 1 se REPROVADO.
|
|
170
224
|
- Sem planejamento.
|
|
@@ -182,8 +236,9 @@ Pra gates pre-merge em CI.
|
|
|
182
236
|
## Constitution Gate
|
|
183
237
|
|
|
184
238
|
<critical>
|
|
185
|
-
-
|
|
186
|
-
-
|
|
239
|
+
- Finding SECRET → verdict NUNCA pode ser APROVADO (sem escape via ADR). Rotacione e remova.
|
|
240
|
+
- Finding CRITICAL/HIGH/COMPROMISED (CVE ou SAST alcançável) sem ADR justificando aceitação explícita → verdict não pode ser APROVADO.
|
|
241
|
+
- Violações de princípios de constitution security-related (P-009 server-side auth, P-010 secrets-in-repo, P-011 sem SAST high-severity) escalonam findings — violação de princípio `severity: info` surface aqui vira HIGH.
|
|
187
242
|
</critical>
|
|
188
243
|
|
|
189
244
|
## Anti-patterns
|
|
@@ -198,8 +253,10 @@ Pra gates pre-merge em CI.
|
|
|
198
253
|
|
|
199
254
|
```
|
|
200
255
|
.dw/secure-audit/
|
|
201
|
-
├── audit-summary.md # verdict + resumo de tiers
|
|
256
|
+
├── audit-summary.md # verdict + resumo de tiers + status dos scanners
|
|
202
257
|
├── owasp-findings.md # Camada 1
|
|
258
|
+
├── sast-findings.md # Camada 4 (Semgrep)
|
|
259
|
+
├── secret-findings.md # Camada 5 (gitleaks, redacted)
|
|
203
260
|
├── trivy-findings.md # Camada 2 (SCA + secrets + IaC)
|
|
204
261
|
├── lockfile-findings.md # Camada 2 (native auditor)
|
|
205
262
|
├── compromise-findings.md # Camada 3
|
|
@@ -80,6 +80,7 @@ O comando `update` sobrescreve arquivos gerenciados e PRESERVA:
|
|
|
80
80
|
- `.dw/rules/` (rules do usuário)
|
|
81
81
|
- `.dw/spec/` (PRDs e tasks em andamento)
|
|
82
82
|
- `.dw/intel/` (índice de codebase do `/dw-intel --build`)
|
|
83
|
+
- docs derivados do projeto como `.dw/constitution.md`, `.dw/rules/concerns.md` e `DESIGN.md` em frontend
|
|
83
84
|
|
|
84
85
|
O comando `update` também roda o passo de migração GSD automaticamente — se o projeto tem `.planning/` legado (de uso prévio do GSD), o conteúdo é migrado para `.dw/intel/`, `.dw/spec/active-session.md`, `.dw/spec/quick/`, etc., e `.planning/` é renomeado para `.planning.gsd-archive-<DATA>/` para inspeção. Os arquivos `.claude/commands/gsd/`, `.claude/agents/gsd-*.md`, `.claude/hooks/gsd-*.js` e `.claude/gsd-file-manifest.json` são removidos durante a migração.
|
|
85
86
|
|
|
@@ -97,9 +98,23 @@ Apresente ao usuário:
|
|
|
97
98
|
- Idioma detectado (`DETECTED_LANG`)
|
|
98
99
|
- Versão anterior → nova versão
|
|
99
100
|
- Resumo do que o output do `update` mostrou (arquivos copiados, wrappers gerados, MCPs configurados)
|
|
101
|
+
- As `Post-update agent actions` impressas pelo CLI
|
|
100
102
|
- Quaisquer avisos ou erros
|
|
101
103
|
|
|
102
|
-
### 6.
|
|
104
|
+
### 6. Executar Ações de Agente Pós-Update (Obrigatório)
|
|
105
|
+
|
|
106
|
+
<critical>O CLI não consegue executar slash commands nem inspecionar sozinho a autoridade de design específica do produto. Quando o output do update imprimir `Post-update agent actions`, trate essa lista como trabalho para este agente executar agora, exceto se o usuário pediu explicitamente "só atualize os arquivos".</critical>
|
|
107
|
+
|
|
108
|
+
Rode os comandos listados nesta ordem:
|
|
109
|
+
|
|
110
|
+
1. `/dw-analyze-project` quando listado — refresca docs derivados do projeto. Este é o comando que cria ou atualiza `.dw/rules/`, oferece `.dw/constitution.md`, escreve `.dw/rules/concerns.md` e, em projetos frontend, sintetiza `DESIGN.md` a partir dos tokens existentes quando não há autoridade de design.
|
|
111
|
+
2. `/dw-intel --build` quando listado — reconstrói o índice queryable do codebase depois do refresh de rules/docs.
|
|
112
|
+
3. `/dw-harness-audit` — valida commands, wrappers, agentes, MCPs e gates depois que arquivos gerenciados mudaram.
|
|
113
|
+
4. `/dw-skill-health` — audita bundled skills e agentes atualizados por bloat, sobreposição e referências antigas.
|
|
114
|
+
|
|
115
|
+
Se `/dw-analyze-project` fizer perguntas de esclarecimento ou aprovação, faça-as e continue. Não fabrique `DESIGN.md`, `concerns.md` ou constitution diretamente dentro de `/dw-update`; delegue para o comando dono desses artefatos.
|
|
116
|
+
|
|
117
|
+
### 7. Sugerir Próximo Passo
|
|
103
118
|
|
|
104
119
|
Se comandos/skills foram atualizados, lembre o usuário:
|
|
105
120
|
- Reinicie a sessão do agente (ou recarregue skills) para que as instruções novas tenham efeito — skills costumam ser carregadas no início da sessão
|
|
@@ -80,12 +80,17 @@ mode: defaults | custom
|
|
|
80
80
|
**P-009 — Authorization server-side em todo endpoint que altera estado** (severity: info)
|
|
81
81
|
**Regra:** Endpoint que cria, atualiza ou deleta dado deve verificar autorização do caller no servidor. Gating em UI (botões escondidos, formulários disabled) não é segurança.
|
|
82
82
|
**Why:** Browsers são untrusted (ver `dw-testing-discipline/references/security-boundary.md`). Gating em UI é conveniência; só checks server-side protegem dado.
|
|
83
|
-
**Enforcement:** `dw-
|
|
83
|
+
**Enforcement:** `dw-review` e o Security Gate `dw-secure-audit` exigem check de auth explícito (decorator, middleware ou assertion in-handler) em rotas POST/PUT/PATCH/DELETE.
|
|
84
84
|
|
|
85
|
-
**P-010 — Secrets nunca entram no repositório** (severity:
|
|
85
|
+
**P-010 — Secrets nunca entram no repositório** (severity: high)
|
|
86
86
|
**Regra:** Nenhuma API key, password, signing key, token ou endpoint de produção commitado em source. `.env.example` documenta forma apenas.
|
|
87
87
|
**Why:** Histórico de repositório é permanente. Um secret commitado uma vez está vazado mesmo que revertido no commit seguinte.
|
|
88
|
-
**Enforcement:** `dw-
|
|
88
|
+
**Enforcement:** o Security Gate `dw-secure-audit` roda gitleaks + Trivy no diff. Qualquer hit bloqueia — **sem exceção de ADR** (rotacione, não justifique).
|
|
89
|
+
|
|
90
|
+
**P-011 — Nenhum finding SAST high-severity passa sem revisão** (severity: high)
|
|
91
|
+
**Regra:** Código gerado/alterado deve passar na camada SAST (Semgrep) do Security Gate. Um finding high-severity alcançável (SQLi, command/code injection, SSRF, deserialization insegura, authn bypass) bloqueia salvo ADR justificando aceitação.
|
|
92
|
+
**Why:** Código gerado por IA reproduz padrões inseguros em escala; SAST determinístico no diff pega o que o review por leitura perde.
|
|
93
|
+
**Enforcement:** `dw-secure-audit` roda Semgrep no diff (`--baseline-commit`); findings sobrevivem a uma validação fp-check de reachability antes de bloquear.
|
|
89
94
|
|
|
90
95
|
---
|
|
91
96
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Módulo de fluxo do functional-doc. Executado por .dw/scripts/functional-doc/run-playwright-flow.mjs
|
|
2
|
+
// através da API Node do Playwright, para que o vídeo seja gravado com page.screencast (funciona tanto
|
|
3
|
+
// com browser lançado quanto via connectOverCDP). Não precisa de imports aqui — o runner injeta
|
|
4
|
+
// page, context, expect, baseURL e os helpers step()/shot().
|
|
5
|
+
|
|
6
|
+
export default async function flow({ page, expect, baseURL, step, shot }) {
|
|
7
|
+
await step("Abrir rota alvo", async () => {
|
|
8
|
+
await page.goto(`${baseURL}{{routePath}}`);
|
|
9
|
+
await expect(page).toHaveURL(new RegExp("{{routeRegex}}"));
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
{{testSteps}}
|
|
13
|
+
|
|
14
|
+
await step("Registrar contexto final", async () => {
|
|
15
|
+
await expect(page.locator("body")).toBeVisible();
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "cdp-relay"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
description = "Tiny TCP forwarder so WSL can reach a Windows browser's CDP debug port in NAT mode. Built on Windows by dev-workflow; no runtime dependency."
|
|
6
|
+
|
|
7
|
+
[[bin]]
|
|
8
|
+
name = "cdp-relay"
|
|
9
|
+
path = "src/main.rs"
|
|
10
|
+
|
|
11
|
+
[profile.release]
|
|
12
|
+
opt-level = "z"
|
|
13
|
+
lto = true
|
|
14
|
+
strip = true
|
|
15
|
+
panic = "abort"
|
|
16
|
+
codegen-units = 1
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//! cdp-relay — a tiny TCP forwarder.
|
|
2
|
+
//!
|
|
3
|
+
//! Listens on 0.0.0.0:<listen> and forwards every connection to 127.0.0.1:<target>.
|
|
4
|
+
//! dev-workflow runs this on the Windows side so WSL (NAT networking) can reach a Windows
|
|
5
|
+
//! browser's CDP remote-debugging port, which Chromium binds to loopback only. std-only:
|
|
6
|
+
//! no crates, no runtime — a single static .exe built with the user's Windows `cargo`.
|
|
7
|
+
|
|
8
|
+
use std::env;
|
|
9
|
+
use std::io;
|
|
10
|
+
use std::net::{Shutdown, TcpListener, TcpStream};
|
|
11
|
+
use std::thread;
|
|
12
|
+
|
|
13
|
+
fn pump(mut from: TcpStream, mut to: TcpStream) {
|
|
14
|
+
let _ = io::copy(&mut from, &mut to);
|
|
15
|
+
// Signal EOF to the peer so the other direction can finish cleanly.
|
|
16
|
+
let _ = to.shutdown(Shutdown::Write);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fn handle(client: TcpStream, target_port: u16) -> io::Result<()> {
|
|
20
|
+
client.set_nodelay(true).ok();
|
|
21
|
+
let upstream = TcpStream::connect(("127.0.0.1", target_port))?;
|
|
22
|
+
upstream.set_nodelay(true).ok();
|
|
23
|
+
|
|
24
|
+
let client_rx = client.try_clone()?;
|
|
25
|
+
let upstream_rx = upstream.try_clone()?;
|
|
26
|
+
// client -> upstream
|
|
27
|
+
thread::spawn(move || pump(client, upstream));
|
|
28
|
+
// upstream -> client
|
|
29
|
+
thread::spawn(move || pump(upstream_rx, client_rx));
|
|
30
|
+
Ok(())
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
fn main() {
|
|
34
|
+
let args: Vec<String> = env::args().collect();
|
|
35
|
+
if args.len() < 3 {
|
|
36
|
+
eprintln!("usage: cdp-relay <listen_port> <target_port>");
|
|
37
|
+
std::process::exit(2);
|
|
38
|
+
}
|
|
39
|
+
let listen_port: u16 = args[1].parse().expect("invalid listen port");
|
|
40
|
+
let target_port: u16 = args[2].parse().expect("invalid target port");
|
|
41
|
+
|
|
42
|
+
let listener = TcpListener::bind(("0.0.0.0", listen_port)).expect("bind failed");
|
|
43
|
+
for stream in listener.incoming() {
|
|
44
|
+
if let Ok(client) = stream {
|
|
45
|
+
// One connection failing must not take down the relay.
|
|
46
|
+
let _ = handle(client, target_port);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -628,7 +628,7 @@ function toTitleCase(value) {
|
|
|
628
628
|
function buildPlaywrightSteps(features, heading, s) {
|
|
629
629
|
const safeHeading = heading.replace(/"/g, '\\"');
|
|
630
630
|
const steps = [
|
|
631
|
-
` await
|
|
631
|
+
` await step("${s.validateInitialLoad}", async () => {`,
|
|
632
632
|
` await expect(page.getByText(/${escapeRegex(safeHeading)}/i).first()).toBeVisible();`,
|
|
633
633
|
` });`,
|
|
634
634
|
];
|
|
@@ -636,8 +636,8 @@ function buildPlaywrightSteps(features, heading, s) {
|
|
|
636
636
|
const firstEdge = features.flatMap((feature) => feature.cases).find((item) => item.type === "edge-case");
|
|
637
637
|
if (firstEdge) {
|
|
638
638
|
steps.push(
|
|
639
|
-
` await
|
|
640
|
-
` await
|
|
639
|
+
` await step("${s.recordEdgeCase}", async () => {`,
|
|
640
|
+
` await shot("edge-case");`,
|
|
641
641
|
` });`,
|
|
642
642
|
);
|
|
643
643
|
}
|
|
@@ -645,7 +645,7 @@ function buildPlaywrightSteps(features, heading, s) {
|
|
|
645
645
|
const firstError = features.flatMap((feature) => feature.cases).find((item) => item.type === "error");
|
|
646
646
|
if (firstError) {
|
|
647
647
|
steps.push(
|
|
648
|
-
` await
|
|
648
|
+
` await step("${s.recordErrorCase}", async () => {`,
|
|
649
649
|
` await expect(page.locator("body")).toBeVisible();`,
|
|
650
650
|
` });`,
|
|
651
651
|
);
|
|
@@ -715,7 +715,7 @@ function buildManifest({ projectRoot, target, targetType, routePath, baseUrl, ha
|
|
|
715
715
|
features: path.join(outputRoot, "features.md"),
|
|
716
716
|
caseMatrix: path.join(outputRoot, "case-matrix.md"),
|
|
717
717
|
e2eRunbook: path.join(outputRoot, "e2e-runbook.md"),
|
|
718
|
-
script: path.join(outputRoot, "scripts", `${slugify(routePath || target)}.
|
|
718
|
+
script: path.join(outputRoot, "scripts", `${slugify(routePath || target)}.flow.mjs`),
|
|
719
719
|
captions: path.join(outputRoot, "captions", `${slugify(routePath || target)}.srt`),
|
|
720
720
|
},
|
|
721
721
|
blockers: hasPlaywright ? [] : ["Playwright configuration not detected"],
|
|
@@ -786,10 +786,8 @@ function main() {
|
|
|
786
786
|
);
|
|
787
787
|
|
|
788
788
|
writeFile(
|
|
789
|
-
path.join(outputRoot, "scripts", `${slugify(routePath || target)}.
|
|
790
|
-
renderTemplate(path.join(templatesRoot, "playwright.
|
|
791
|
-
baseUrl,
|
|
792
|
-
testTitle: s.flowTest(routePath || target),
|
|
789
|
+
path.join(outputRoot, "scripts", `${slugify(routePath || target)}.flow.mjs`),
|
|
790
|
+
renderTemplate(path.join(templatesRoot, "playwright.flow.mjs.tpl"), {
|
|
793
791
|
routePath,
|
|
794
792
|
routeRegex: escapeRegex(routePath || "/"),
|
|
795
793
|
testSteps: buildPlaywrightSteps(features, heading, s),
|