bmad-plus 0.19.0 → 0.21.0
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/CHANGELOG.md +35 -0
- package/README.md +15 -15
- package/package.json +1 -1
- package/readme-international/README.de.md +15 -15
- package/readme-international/README.es.md +15 -15
- package/readme-international/README.fr.md +15 -15
- package/src/bmad-plus/agents/agent-quality/SKILL.md +1 -1
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/code-review.md +39 -4
- package/src/bmad-plus/packs/pack-seo/scripts/seo_crawl.py +36 -24
- package/src/bmad-plus/packs/pack-seo/scripts/seo_fetch.py +179 -59
- package/src/bmad-plus/skills/bmad-plus-uat/ref/uat-results.schema.json +1 -0
- package/tools/cli/bmad-plus-cli.js +16 -4
- package/tools/cli/commands/review.js +258 -22
- package/tools/cli/commands/uat.js +16 -3
- package/tools/cli/lib/glob.js +73 -0
- package/tools/cli/lib/packs.js +1 -1
- package/tools/cli/lib/redact.js +116 -0
- package/tools/cli/lib/review-rules.js +186 -0
- package/tools/cli/lib/review.js +598 -30
- package/tools/cli/lib/uat.js +16 -0
- package/tools/cli/review-rules/ci-workflows.md +7 -0
- package/tools/cli/review-rules/configuration.md +5 -0
- package/tools/cli/review-rules/containers.md +6 -0
- package/tools/cli/review-rules/general.md +10 -0
- package/tools/cli/review-rules/index.yaml +45 -0
- package/tools/cli/review-rules/javascript-typescript.md +7 -0
- package/tools/cli/review-rules/python.md +6 -0
- package/tools/cli/review-rules/shell.md +6 -0
- package/tools/cli/review-rules/sql-and-migrations.md +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,41 @@ All notable changes to BMAD+ will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.21.0] - 2026-09-28
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Review run record.** `coverage.json` can carry `run {stop, detail?, passes, attempts[], tokens?, durationMs?}`. Stop reasons are `completed`, `budget`, `time-limit`, `failure-streak` or `interrupted`; any stop other than `completed` needs a detail, and a review that stopped early is always `incomplete`. Usage is recorded only when the host reports it, never estimated. After three consecutive failed attempts a unit is abandoned and a fourth attempt is refused.
|
|
13
|
+
- **`review gate --emit-check <file>`** writes the verdict as `bmad-plus/review-check/1` for CI, atomically and without a timestamp, so the same evidence always gives the same bytes. It lists open findings by severity with their anchored lines and a `github` block shaped for the check-runs API. Exit codes are unchanged. The gate's reasons are redacted once, so the terminal, `--json` and the check carry the same text.
|
|
14
|
+
- **`review continue <id>`** resumes an interrupted review on the same sealed scope and writes `continue.json`: units and files still owed, abandoned files, findings to requote, passes left. It refuses when the head, the rules or a selected file changed, and points to a new scope and `review compare`.
|
|
15
|
+
- **Rule groups.** A rule can name a `group`; units list their groups so parallel reviewers can split a unit by rule family, and a unit is complete as a whole or when every group is done. Built-in groups are `code`, `data` and `delivery`; the group is part of the rule-set hash.
|
|
16
|
+
- **Review bench** (maintainer tool, not in the npm package): seven small repositories in seven languages with 12 planted defects and 8 decoys, a published matching rule (path, category and a located quote that points at one plant; never a line number), and a scorer reporting recall, precision, decoy hits, unlocated quotes and reported usage. Three reference runs are replayed by a blocking CI step. No model call.
|
|
17
|
+
- **CI review recipes** (`docs/recipes/ci-review/`): copy-ready workflows that seal the scope and gate a pull request with a host agent on a self-hosted runner. They are read-only, read no secret, pin every action, trust nothing the agent can rewrite (a step output holds a digest of the sealed scope), and fail fork pull requests instead of letting a required check pass unreviewed.
|
|
18
|
+
- The open-code-review study states how the bench decides whether an optional `ocr` bridge is ever built.
|
|
19
|
+
|
|
20
|
+
### Security
|
|
21
|
+
|
|
22
|
+
- **SEO fetcher and crawler: SSRF protection and connection pinning.** Each host is resolved by the scripts, any non-public address is refused, and the connection goes to the exact address that was validated, on the first request and on every redirect hop, which defeats DNS rebinding. The guard sits in the connection pool every `requests` release goes through (verified on 2.34, 2.31 and 2.28). URL credentials, invalid ports, CGNAT and site-local ranges and IPv4-mapped or NAT64 forms of internal addresses are refused; proxies and `~/.netrc` are not used; custom CA bundles are still honoured.
|
|
23
|
+
- **MCP knowledge ingestion is confined to each source checkout.** Paths resolving outside the checkout are refused; symlinks and `.git` are never followed.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **MCP server stack modernized** on Python 3.12: official `mcp` SDK, chromadb 1.5, sentence-transformers 6.1, CPU-only torch. `RAG_EMBEDDING_MODEL` selects the embedding model and Chroma telemetry is off. Existing stores open in place; re-run `ingest.py` once after upgrading. Chunks are keyed by their path in the checkout and stale chunks are pruned after each pass that indexed something. An offline smoke (`mcp-server/ci/smoke.py`) ingests a fixture, lists tools, queries and merges PDFs over an authenticated MCP session.
|
|
28
|
+
|
|
29
|
+
## [0.20.0] - 2026-09-28
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **Review rules by path.** `review scope` writes `checklist.md`: each rule that applies to the changed paths, once, with the files it covers. Eight built-in rules written for BMAD+ (general, JavaScript/TypeScript, Python, SQL and migrations, shell, CI workflows, containers, configuration); a project adds, replaces or disables rules in `_bmad/review-rules.yaml`, whose documents are confined to `_bmad/` and size-capped. The rule set is part of the scope hash. A finding may name its `rule`; one that does not apply to its path is refused. `review rules [path]` shows the effective rules.
|
|
34
|
+
- **Effort.** `review scope --effort low|medium|high` seals the depth in the scope and prints a plan: passes, refutation, survey first on large changes, parallel units when there are several.
|
|
35
|
+
- **`review compare <id> --since <earlier-id>`** sorts findings into new, persisting, refuted, resolved and not reviewed. A finding is matched by path, category and quote, never by line; renamed files are followed. A finding gone from a file the later review did not complete is not reviewed, never resolved.
|
|
36
|
+
- **Redaction floor.** Credential-like values (key blocks, URL credentials, authorization headers, credential-named assignments, well-known token shapes) become `[REDACTED]` in anchored review findings and in acceptance-run notes before `uat serve` or `uat import` writes them; references such as `process.env.X` or `${{ secrets.X }}` are kept. Each record counts its `redactions`.
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- Every command gives the terminal back. In an interactive terminal the CLI kept its standard input open after the command had finished, so the shell prompt only returned after Ctrl+C. A test now runs the CLI under a pseudo-terminal whose input stays open.
|
|
41
|
+
- The release workflow tolerates a distribution remote left by an earlier run on a self-hosted runner, and always removes the distribution credential from the workspace at the end of the job.
|
|
42
|
+
|
|
8
43
|
## [0.19.0] - 2026-09-27
|
|
9
44
|
|
|
10
45
|
### Added
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# BMAD+
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/bmad-plus)
|
|
4
4
|
|
|
5
|
-
**Version 0.
|
|
5
|
+
**Version 0.21.0** · Node.js `>=20.0.0` · MIT
|
|
6
6
|
|
|
7
7
|
Project-local AI development workflows with clear roles, shared context, safe updates and coding-tool adapters
|
|
8
8
|
|
|
@@ -35,7 +35,7 @@ Run the installer. Select the adapters for the AI tools you use and the packs yo
|
|
|
35
35
|
**In your project terminal:**
|
|
36
36
|
|
|
37
37
|
```sh
|
|
38
|
-
npx bmad-plus@0.
|
|
38
|
+
npx bmad-plus@0.21.0 install
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
The installer creates the agent instructions, shared project spine and selected tool adapters. Optional packs may need additional runtimes or API access.
|
|
@@ -71,7 +71,7 @@ Ask Sentinel to check the change against its acceptance criteria. Ask for test e
|
|
|
71
71
|
**In your AI assistant:**
|
|
72
72
|
|
|
73
73
|
```text
|
|
74
|
-
Sentinel, review this change against the acceptance criteria. Check the main success and failure paths, report remaining issues and summarize what the next session needs to know. If the BMAD+ CLI is available, seal the scope with bmad-plus review scope, quote the code of every finding, account for every selected file, then report what bmad-plus review gate answers.
|
|
74
|
+
Sentinel, review this change against the acceptance criteria. Check the main success and failure paths, report remaining issues and summarize what the next session needs to know. If the BMAD+ CLI is available, seal the scope with bmad-plus review scope, apply the rules in its checklist, quote the code of every finding, account for every selected file, then report what bmad-plus review gate answers.
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
Read the changes and test results. The assistant follows the permissions and capabilities of its host tool.
|
|
@@ -171,18 +171,18 @@ Read AGENTS.md and the available project memory. Summarize the last verified sta
|
|
|
171
171
|
|
|
172
172
|
Expected result: a short, evidence-based restart. Project notes are useful context and still need to be checked against the current work.
|
|
173
173
|
|
|
174
|
-
## What’s new in 0.
|
|
174
|
+
## What’s new in 0.21.0
|
|
175
175
|
|
|
176
|
-
|
|
176
|
+
Reviews that stop honestly, resume, and report to CI
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
A review now records why it stopped and what it used, writes a check a CI step can read, and resumes on the scope it sealed. The SEO fetcher connects only to addresses it has validated, and the MCP server moves to the official SDK on Python 3.12. Nothing changes in how you install or update.
|
|
179
179
|
|
|
180
|
-
-
|
|
181
|
-
-
|
|
182
|
-
- bmad-plus review
|
|
183
|
-
-
|
|
184
|
-
-
|
|
185
|
-
-
|
|
180
|
+
- coverage.json can record how a review ran: why it stopped (completed, budget, time limit, three failed attempts in a row, interrupted), the passes run and the usage the host reported. A review that stopped early is always incomplete, and a unit is abandoned after three consecutive failed attempts.
|
|
181
|
+
- bmad-plus review gate --emit-check followed by a file name writes the verdict as a check document for CI: disposition, reasons, open findings by severity with their lines, and a block shaped for GitHub check runs. The same evidence always gives the same file.
|
|
182
|
+
- bmad-plus review continue resumes an interrupted review on the same sealed scope and lists what is still owed. It refuses when the code, the rules or a selected file changed, and points to a new scope and review compare.
|
|
183
|
+
- Review rules can belong to a group (code, data, delivery or your own), so parallel reviewers can split a unit by rule family.
|
|
184
|
+
- For maintainers, a review bench scores recorded review answers against planted defects and decoys with a published matching rule, and copy-ready CI recipes gate pull requests with a host agent on a self-hosted runner without trusting anything the agent can rewrite.
|
|
185
|
+
- The SEO fetcher and crawler resolve each host themselves, refuse internal addresses and connect to the exact address they validated, on every redirect too, which defeats DNS rebinding. The MCP server uses the official SDK on Python 3.12 with current chromadb and sentence-transformers; re-run ingest.py once after upgrading.
|
|
186
186
|
|
|
187
187
|
## Version History
|
|
188
188
|
|
|
@@ -190,9 +190,9 @@ These dates identify reviewed CHANGELOG notes, not npm publication dates. The we
|
|
|
190
190
|
|
|
191
191
|
| Version | Release-notes date | Reviewed summary |
|
|
192
192
|
| --- | --- | --- |
|
|
193
|
+
| 0.21.0 | 2026-09-28 | A review now records why it stopped and what it used, writes a check a CI step can read, and resumes on the scope it sealed. The SEO fetcher connects only to addresses it has validated, and the MCP server moves to the official SDK on Python 3.12. Nothing changes in how you install or update. |
|
|
194
|
+
| 0.20.0 | 2026-09-28 | bmad-plus review now hands the reviewer the rules that apply to the changed files, fixes the depth of a review before it starts, compares a review with an earlier one without calling an unchecked finding fixed, and masks credentials in what it writes. Nothing changes in how you install or update. |
|
|
193
195
|
| 0.19.0 | 2026-09-27 | bmad-plus review seals what a review must cover, locates every finding by the code it quotes, and derives the verdict from coverage instead of the number of findings. Review triage now keeps a finding unless a quoted ground refutes it. Nothing changes in how you install or update. |
|
|
194
|
-
| 0.18.0 | 2026-09-25 | The acceptance page now verifies every save, restores your answers on reload before anything else, keeps runs from other revisions and other tabs apart, and names sixteen guarantees the build refuses to lose. Nothing changes in how you install or update; rebuild your recipe pages to get the new page. |
|
|
195
|
-
| 0.17.1 | 2026-09-24 | Installing over a different version now stops and points to update, re-installs keep your settings, and updates remove files a version no longer ships while keeping a restorable backup. Some install behaviors changed; review your scripts before rerunning them. |
|
|
196
196
|
|
|
197
197
|
[Release history and update guide](https://bmad-plus.rochetta.fr/docs/#changelog) · [All published npm versions](https://www.npmjs.com/package/bmad-plus?activeTab=versions)
|
|
198
198
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "bmad-plus",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.21.0",
|
|
5
5
|
"description": "Project-local AI development workflows with clear roles, shared context, safe updates and coding-tool adapters",
|
|
6
6
|
"homepage": "https://bmad-plus.rochetta.fr",
|
|
7
7
|
"keywords": [
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
<a href="../README.md">English</a> | <a href="README.fr.md">Français</a> | <a href="README.es.md">Español</a> | 🌐 <b>Deutsch</b>
|
|
5
5
|
</div>
|
|
6
6
|
|
|
7
|
-
[](https://www.npmjs.com/package/bmad-plus)
|
|
8
8
|
|
|
9
|
-
**Version 0.
|
|
9
|
+
**Version 0.21.0** · Node.js `>=20.0.0` · MIT
|
|
10
10
|
|
|
11
11
|
Projektlokale KI-Entwicklungsworkflows mit klaren Rollen, gemeinsamem Kontext, sicheren Updates und Adaptern für Coding-Tools.
|
|
12
12
|
|
|
@@ -39,7 +39,7 @@ Starte das Installationsprogramm. Wähle die Adapter deiner KI-Werkzeuge und die
|
|
|
39
39
|
**Im Terminal deines Projekts:**
|
|
40
40
|
|
|
41
41
|
```sh
|
|
42
|
-
npx bmad-plus@0.
|
|
42
|
+
npx bmad-plus@0.21.0 install
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
Die Installation erstellt Agentenanweisungen, die gemeinsame Projektbasis und die gewählten Adapter. Optionale Packs können weitere Laufzeitumgebungen oder API-Zugänge benötigen.
|
|
@@ -75,7 +75,7 @@ Bitte Sentinel, die Änderung anhand der Akzeptanzkriterien zu prüfen. Fordere
|
|
|
75
75
|
**In deinem KI-Assistenten:**
|
|
76
76
|
|
|
77
77
|
```text
|
|
78
|
-
Sentinel, prüfe diese Änderung anhand der Akzeptanzkriterien. Überprüfe die wichtigsten Erfolgs- und Fehlerfälle, nenne offene Probleme und fasse zusammen, was die nächste Sitzung wissen muss. Wenn das BMAD+ CLI verfügbar ist, versiegle den Umfang mit bmad-plus review scope, zitiere den Code jedes Befunds, belege jede ausgewählte Datei und berichte, was bmad-plus review gate antwortet.
|
|
78
|
+
Sentinel, prüfe diese Änderung anhand der Akzeptanzkriterien. Überprüfe die wichtigsten Erfolgs- und Fehlerfälle, nenne offene Probleme und fasse zusammen, was die nächste Sitzung wissen muss. Wenn das BMAD+ CLI verfügbar ist, versiegle den Umfang mit bmad-plus review scope, wende die Regeln seiner Checkliste an, zitiere den Code jedes Befunds, belege jede ausgewählte Datei und berichte, was bmad-plus review gate antwortet.
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
Lies die Änderungen und Testergebnisse. Der Assistent arbeitet innerhalb der Rechte und Fähigkeiten seines Host-Werkzeugs.
|
|
@@ -175,18 +175,18 @@ Lies AGENTS.md und die verfügbare Projekterinnerung. Fasse den letzten geprüft
|
|
|
175
175
|
|
|
176
176
|
Erwartetes Ergebnis: ein kurzer, belegter Wiedereinstieg. Projektnotizen liefern Kontext und müssen mit dem aktuellen Stand abgeglichen werden.
|
|
177
177
|
|
|
178
|
-
## Neu in 0.
|
|
178
|
+
## Neu in 0.21.0
|
|
179
179
|
|
|
180
|
-
|
|
180
|
+
Reviews, die ehrlich anhalten, fortgesetzt werden und an die CI berichten
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
Ein Review hält jetzt fest, warum es angehalten hat und was es verbraucht hat, schreibt eine Prüfung, die ein CI-Schritt lesen kann, und wird auf dem versiegelten Umfang fortgesetzt. Der SEO-Abruf verbindet sich nur mit Adressen, die er geprüft hat, und der MCP-Server wechselt zum offiziellen SDK unter Python 3.12. An Installation und Update ändert sich nichts.
|
|
183
183
|
|
|
184
|
-
-
|
|
185
|
-
-
|
|
186
|
-
- bmad-plus review
|
|
187
|
-
-
|
|
188
|
-
-
|
|
189
|
-
-
|
|
184
|
+
- coverage.json kann festhalten, wie ein Review verlief: warum es anhielt (abgeschlossen, Budget, Zeitlimit, drei Fehlversuche in Folge, unterbrochen), die ausgeführten Durchgänge und die vom Host gemeldete Nutzung. Ein vorzeitig angehaltenes Review ist immer unvollständig, und eine Einheit wird nach drei Fehlversuchen in Folge aufgegeben.
|
|
185
|
+
- bmad-plus review gate --emit-check mit einem Dateinamen schreibt das Urteil als Prüfdokument für die CI: Ergebnis, Gründe, offene Befunde nach Schwere mit ihren Zeilen und einen Block im Format der GitHub-Check-Runs. Dieselben Belege ergeben immer dieselbe Datei.
|
|
186
|
+
- bmad-plus review continue setzt ein unterbrochenes Review auf demselben versiegelten Umfang fort und listet, was noch aussteht. Es verweigert, wenn sich Code, Regeln oder eine ausgewählte Datei geändert haben, und verweist auf einen neuen Umfang und review compare.
|
|
187
|
+
- Review-Regeln können einer Gruppe angehören (code, data, delivery oder eine eigene), damit parallele Prüfende eine Einheit nach Regelfamilie aufteilen.
|
|
188
|
+
- Für Maintainer bewertet ein Review-Prüfstand aufgezeichnete Review-Antworten gegen eingebaute Fehler und Köder mit einer veröffentlichten Zuordnungsregel, und kopierfertige CI-Vorlagen lassen einen Pull Request von einem Host-Agenten auf einem selbst gehosteten Runner prüfen, ohne etwas zu vertrauen, das der Agent umschreiben kann.
|
|
189
|
+
- SEO-Abruf und Crawler lösen jeden Host selbst auf, lehnen interne Adressen ab und verbinden sich genau mit der geprüften Adresse, auch bei jeder Weiterleitung, was DNS-Rebinding verhindert. Der MCP-Server nutzt das offizielle SDK unter Python 3.12 mit aktuellem chromadb und sentence-transformers; führe ingest.py nach dem Update einmal erneut aus.
|
|
190
190
|
|
|
191
191
|
## Versionsverlauf
|
|
192
192
|
|
|
@@ -194,9 +194,9 @@ Diese Daten bezeichnen geprüfte CHANGELOG-Einträge, nicht die Veröffentlichun
|
|
|
194
194
|
|
|
195
195
|
| Version | Datum der Notizen | Geprüfte Zusammenfassung |
|
|
196
196
|
| --- | --- | --- |
|
|
197
|
+
| 0.21.0 | 2026-09-28 | Ein Review hält jetzt fest, warum es angehalten hat und was es verbraucht hat, schreibt eine Prüfung, die ein CI-Schritt lesen kann, und wird auf dem versiegelten Umfang fortgesetzt. Der SEO-Abruf verbindet sich nur mit Adressen, die er geprüft hat, und der MCP-Server wechselt zum offiziellen SDK unter Python 3.12. An Installation und Update ändert sich nichts. |
|
|
198
|
+
| 0.20.0 | 2026-09-28 | bmad-plus review gibt der prüfenden Person jetzt die Regeln, die für die geänderten Dateien gelten, legt die Tiefe eines Reviews vor Beginn fest, vergleicht ein Review mit einem früheren, ohne einen ungeprüften Befund für behoben zu erklären, und schwärzt Zugangsdaten in dem, was es schreibt. An Installation und Update ändert sich nichts. |
|
|
197
199
|
| 0.19.0 | 2026-09-27 | bmad-plus review versiegelt, was ein Review abdecken muss, findet jeden Befund über den Code, den er zitiert, und leitet das Urteil aus der Abdeckung ab statt aus der Zahl der Befunde. Die Review-Sichtung behält einen Befund jetzt, solange kein zitierter Grund ihn widerlegt. An Installation und Update ändert sich nichts. |
|
|
198
|
-
| 0.18.0 | 2026-09-25 | Die Abnahmeseite prüft jetzt jedes Speichern, stellt deine Antworten beim Neuladen vor allem anderen wieder her, hält Durchläufe anderer Fassungen und anderer Tabs auseinander und benennt sechzehn Garantien, die der Build nicht verlieren darf. An Installation und Update ändert sich nichts; baue deine Rezeptseiten neu, um die neue Seite zu erhalten. |
|
|
199
|
-
| 0.17.1 | 2026-09-24 | Eine Installation über eine andere Version bricht jetzt ab und verweist auf update, eine erneute Installation behält deine Einstellungen, und Updates entfernen Dateien, die eine Version nicht mehr mitliefert, mit wiederherstellbarer Sicherung. Einige Installationsabläufe ändern sich: Prüfe deine Skripte, bevor du sie erneut ausführst. |
|
|
200
200
|
|
|
201
201
|
[Versionsverlauf und Update-Anleitung](https://bmad-plus.rochetta.fr/de/docs/#changelog) · [Alle veröffentlichten Versionen auf npm](https://www.npmjs.com/package/bmad-plus?activeTab=versions)
|
|
202
202
|
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
<a href="../README.md">English</a> | <a href="README.fr.md">Français</a> | 🌐 <b>Español</b> | <a href="README.de.md">Deutsch</a>
|
|
5
5
|
</div>
|
|
6
6
|
|
|
7
|
-
[](https://www.npmjs.com/package/bmad-plus)
|
|
8
8
|
|
|
9
|
-
**Versión 0.
|
|
9
|
+
**Versión 0.21.0** · Node.js `>=20.0.0` · MIT
|
|
10
10
|
|
|
11
11
|
Flujos de desarrollo con IA propios de cada proyecto, con roles claros, contexto compartido, actualizaciones seguras y adaptadores para herramientas de programación.
|
|
12
12
|
|
|
@@ -39,7 +39,7 @@ Ejecuta el instalador. Selecciona los adaptadores de tus herramientas de IA y lo
|
|
|
39
39
|
**En la terminal del proyecto:**
|
|
40
40
|
|
|
41
41
|
```sh
|
|
42
|
-
npx bmad-plus@0.
|
|
42
|
+
npx bmad-plus@0.21.0 install
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
El instalador crea las instrucciones de los agentes, la base compartida y los adaptadores seleccionados. Algunos packs opcionales necesitan otros entornos o acceso a API.
|
|
@@ -75,7 +75,7 @@ Pide a Sentinel que compruebe el cambio según los criterios de aceptación. Sol
|
|
|
75
75
|
**En tu asistente de IA:**
|
|
76
76
|
|
|
77
77
|
```text
|
|
78
|
-
Sentinel, revisa este cambio según los criterios de aceptación. Comprueba los principales casos de éxito y fallo, informa de los problemas pendientes y resume lo que necesita saber la próxima sesión. Si el CLI de BMAD+ está disponible, sella el alcance con bmad-plus review scope, cita el código de cada hallazgo, da cuenta de cada archivo seleccionado y comunica lo que responde bmad-plus review gate.
|
|
78
|
+
Sentinel, revisa este cambio según los criterios de aceptación. Comprueba los principales casos de éxito y fallo, informa de los problemas pendientes y resume lo que necesita saber la próxima sesión. Si el CLI de BMAD+ está disponible, sella el alcance con bmad-plus review scope, aplica las reglas de su lista de revisión, cita el código de cada hallazgo, da cuenta de cada archivo seleccionado y comunica lo que responde bmad-plus review gate.
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
Lee los cambios y los resultados de las pruebas. El asistente sigue los permisos y las capacidades de su herramienta anfitriona.
|
|
@@ -175,18 +175,18 @@ Lee AGENTS.md y la memoria de proyecto disponible. Resume el último estado veri
|
|
|
175
175
|
|
|
176
176
|
Resultado esperado: una reanudación breve y fundamentada. Las notas aportan contexto que debe contrastarse con el trabajo actual.
|
|
177
177
|
|
|
178
|
-
## Novedades de la 0.
|
|
178
|
+
## Novedades de la 0.21.0
|
|
179
179
|
|
|
180
|
-
Revisiones
|
|
180
|
+
Revisiones que se detienen con honestidad, se reanudan e informan a la CI
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
Una revisión registra ahora por qué se detuvo y qué consumió, escribe un control que un paso de CI puede leer y se reanuda sobre el alcance que selló. El descargador SEO solo se conecta a direcciones que ha validado, y el servidor MCP pasa al SDK oficial con Python 3.12. Nada cambia en la instalación ni en la actualización.
|
|
183
183
|
|
|
184
|
-
-
|
|
185
|
-
-
|
|
186
|
-
- bmad-plus review
|
|
187
|
-
-
|
|
188
|
-
-
|
|
189
|
-
-
|
|
184
|
+
- coverage.json puede registrar cómo transcurrió una revisión: por qué se detuvo (completada, presupuesto, límite de tiempo, tres intentos fallidos seguidos, interrumpida), las pasadas realizadas y el uso que informó el host. Una revisión detenida antes de tiempo siempre está incompleta, y una unidad se abandona tras tres intentos fallidos consecutivos.
|
|
185
|
+
- bmad-plus review gate --emit-check seguido de un nombre de archivo escribe el veredicto como un documento de control para la CI: disposición, motivos, hallazgos abiertos por gravedad con sus líneas y un bloque con el formato de los check runs de GitHub. Las mismas pruebas dan siempre el mismo archivo.
|
|
186
|
+
- bmad-plus review continue reanuda una revisión interrumpida sobre el mismo alcance sellado y enumera lo que queda pendiente. Se niega cuando cambiaron el código, las reglas o un archivo seleccionado, y remite a un nuevo alcance y a review compare.
|
|
187
|
+
- Las reglas de revisión pueden pertenecer a un grupo (code, data, delivery o uno propio), para que revisores en paralelo se repartan una unidad por familia de reglas.
|
|
188
|
+
- Para mantenedores, un banco de pruebas puntúa respuestas de revisión grabadas frente a defectos sembrados y señuelos con una regla de correspondencia publicada, y recetas de CI listas para copiar hacen pasar una pull request por un agente en un runner autoalojado sin fiarse de nada que el agente pueda reescribir.
|
|
189
|
+
- El descargador y el rastreador SEO resuelven cada host por sí mismos, rechazan direcciones internas y se conectan exactamente a la dirección validada, también en cada redirección, lo que neutraliza el DNS rebinding. El servidor MCP usa el SDK oficial con Python 3.12 y chromadb y sentence-transformers actuales; vuelve a ejecutar ingest.py una vez tras actualizar.
|
|
190
190
|
|
|
191
191
|
## Historial de versiones
|
|
192
192
|
|
|
@@ -194,9 +194,9 @@ Estas fechas identifican las notas revisadas del CHANGELOG, no las fechas de pub
|
|
|
194
194
|
|
|
195
195
|
| Versión | Fecha de las notas | Resumen revisado |
|
|
196
196
|
| --- | --- | --- |
|
|
197
|
+
| 0.21.0 | 2026-09-28 | Una revisión registra ahora por qué se detuvo y qué consumió, escribe un control que un paso de CI puede leer y se reanuda sobre el alcance que selló. El descargador SEO solo se conecta a direcciones que ha validado, y el servidor MCP pasa al SDK oficial con Python 3.12. Nada cambia en la instalación ni en la actualización. |
|
|
198
|
+
| 0.20.0 | 2026-09-28 | bmad-plus review ahora entrega a quien revisa las reglas que se aplican a los archivos modificados, fija la profundidad de una revisión antes de empezar, compara una revisión con otra anterior sin dar por corregido un hallazgo no comprobado y oculta las credenciales en lo que escribe. Nada cambia en la instalación ni en la actualización. |
|
|
197
199
|
| 0.19.0 | 2026-09-27 | bmad-plus review sella lo que una revisión debe cubrir, localiza cada hallazgo por el código que cita y deduce el veredicto de la cobertura en lugar del número de hallazgos. La clasificación de las revisiones conserva ahora un hallazgo mientras ningún motivo citado lo refute. Nada cambia en la instalación ni en la actualización. |
|
|
198
|
-
| 0.18.0 | 2026-09-25 | La página de aceptación ahora verifica cada guardado, restaura tus respuestas al recargar antes que nada, mantiene separadas las pruebas de otras versiones y otras pestañas, y nombra dieciséis garantías que la construcción se niega a perder. Nada cambia en la instalación ni en la actualización; reconstruye tus páginas de receta para obtener la nueva página. |
|
|
199
|
-
| 0.17.1 | 2026-09-24 | Instalar sobre otra versión ahora se detiene y remite a update, una reinstalación conserva tus ajustes y las actualizaciones eliminan los archivos que una versión ya no incluye, con una copia restaurable. Algunos comportamientos de instalación cambian: revisa tus scripts antes de volver a ejecutarlos. |
|
|
200
200
|
|
|
201
201
|
[Historial de versiones y guía de actualización](https://bmad-plus.rochetta.fr/es/docs/#changelog) · [Todas las versiones publicadas en npm](https://www.npmjs.com/package/bmad-plus?activeTab=versions)
|
|
202
202
|
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
<a href="../README.md">English</a> | 🌐 <b>Français</b> | <a href="README.es.md">Español</a> | <a href="README.de.md">Deutsch</a>
|
|
5
5
|
</div>
|
|
6
6
|
|
|
7
|
-
[](https://www.npmjs.com/package/bmad-plus)
|
|
8
8
|
|
|
9
|
-
**Version 0.
|
|
9
|
+
**Version 0.21.0** · Node.js `>=20.0.0` · MIT
|
|
10
10
|
|
|
11
11
|
Des workflows de développement IA propres à chaque projet, avec des rôles clairs, un contexte partagé, des mises à jour sûres et des adaptateurs pour vos outils de code.
|
|
12
12
|
|
|
@@ -39,7 +39,7 @@ Lancez l’installateur. Sélectionnez les adaptateurs de vos outils IA et les p
|
|
|
39
39
|
**Dans le terminal du projet :**
|
|
40
40
|
|
|
41
41
|
```sh
|
|
42
|
-
npx bmad-plus@0.
|
|
42
|
+
npx bmad-plus@0.21.0 install
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
L’installateur crée les instructions des agents, le socle partagé et les adaptateurs sélectionnés. Certains packs facultatifs nécessitent d’autres environnements ou des accès API.
|
|
@@ -75,7 +75,7 @@ Demandez à Sentinel de contrôler le changement selon les critères d’accepta
|
|
|
75
75
|
**Dans votre assistant IA :**
|
|
76
76
|
|
|
77
77
|
```text
|
|
78
|
-
Sentinel, relis ce changement selon les critères d’acceptation. Vérifie les principaux cas de réussite et d’échec, signale les problèmes restants et résume ce que la prochaine session doit savoir. Si le CLI BMAD+ est disponible, scelle le périmètre avec bmad-plus review scope, cite le code de chaque remarque, rends compte de chaque fichier retenu, puis rapporte ce que répond bmad-plus review gate.
|
|
78
|
+
Sentinel, relis ce changement selon les critères d’acceptation. Vérifie les principaux cas de réussite et d’échec, signale les problèmes restants et résume ce que la prochaine session doit savoir. Si le CLI BMAD+ est disponible, scelle le périmètre avec bmad-plus review scope, applique les règles de sa checklist, cite le code de chaque remarque, rends compte de chaque fichier retenu, puis rapporte ce que répond bmad-plus review gate.
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
Relisez les changements et les résultats des tests. L’assistant suit les autorisations et les capacités de son outil hôte.
|
|
@@ -175,18 +175,18 @@ Lis AGENTS.md et la mémoire de projet disponible. Résume le dernier état vér
|
|
|
175
175
|
|
|
176
176
|
Résultat attendu : une reprise courte et fondée sur des éléments vérifiés. Les notes apportent du contexte, à confronter au travail actuel.
|
|
177
177
|
|
|
178
|
-
## Nouveautés de la 0.
|
|
178
|
+
## Nouveautés de la 0.21.0
|
|
179
179
|
|
|
180
|
-
Des revues
|
|
180
|
+
Des revues qui s’arrêtent honnêtement, reprennent et parlent à la CI
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
Une revue enregistre désormais pourquoi elle s’est arrêtée et ce qu’elle a consommé, écrit un contrôle lisible par une étape de CI, et reprend sur le périmètre qu’elle a scellé. Le récupérateur SEO ne se connecte qu’aux adresses qu’il a validées, et le serveur MCP passe au SDK officiel sous Python 3.12. Rien ne change dans l’installation ou la mise à jour.
|
|
183
183
|
|
|
184
|
-
-
|
|
185
|
-
-
|
|
186
|
-
- bmad-plus review
|
|
187
|
-
-
|
|
188
|
-
-
|
|
189
|
-
-
|
|
184
|
+
- coverage.json peut enregistrer le déroulé d’une revue : pourquoi elle s’est arrêtée (terminée, budget, limite de temps, trois échecs de suite, interrompue), les passes faites et l’usage rapporté par l’hôte. Une revue arrêtée avant la fin est toujours incomplète, et une unité est abandonnée après trois échecs consécutifs.
|
|
185
|
+
- bmad-plus review gate --emit-check suivi d’un nom de fichier écrit le verdict sous forme de contrôle pour la CI : disposition, raisons, remarques ouvertes par gravité avec leurs lignes, et un bloc au format des check runs GitHub. Les mêmes preuves donnent toujours le même fichier.
|
|
186
|
+
- bmad-plus review continue reprend une revue interrompue sur le même périmètre scellé et liste ce qui reste dû. Il refuse quand le code, les règles ou un fichier retenu ont changé, et renvoie vers un nouveau périmètre et review compare.
|
|
187
|
+
- Les règles de revue peuvent appartenir à un groupe (code, data, delivery ou le vôtre), pour que des relecteurs parallèles se partagent une unité par famille de règles.
|
|
188
|
+
- Pour les mainteneurs, un banc d’essai note des réponses de revue enregistrées face à des défauts plantés et des leurres, avec une règle de correspondance publiée, et des modèles de CI prêts à copier font passer une pull request par un agent hôte sur un runner auto-hébergé sans rien croire de ce que l’agent peut réécrire.
|
|
189
|
+
- Le récupérateur et le crawler SEO résolvent eux-mêmes chaque hôte, refusent les adresses internes et se connectent exactement à l’adresse validée, redirections comprises, ce qui neutralise le DNS rebinding. Le serveur MCP utilise le SDK officiel sous Python 3.12 avec chromadb et sentence-transformers à jour ; relancez ingest.py une fois après la mise à jour.
|
|
190
190
|
|
|
191
191
|
## Historique des versions
|
|
192
192
|
|
|
@@ -194,9 +194,9 @@ Ces dates identifient les notes relues du CHANGELOG, pas les dates de publicatio
|
|
|
194
194
|
|
|
195
195
|
| Version | Date des notes | Résumé relu |
|
|
196
196
|
| --- | --- | --- |
|
|
197
|
+
| 0.21.0 | 2026-09-28 | Une revue enregistre désormais pourquoi elle s’est arrêtée et ce qu’elle a consommé, écrit un contrôle lisible par une étape de CI, et reprend sur le périmètre qu’elle a scellé. Le récupérateur SEO ne se connecte qu’aux adresses qu’il a validées, et le serveur MCP passe au SDK officiel sous Python 3.12. Rien ne change dans l’installation ou la mise à jour. |
|
|
198
|
+
| 0.20.0 | 2026-09-28 | bmad-plus review donne désormais au relecteur les règles qui s’appliquent aux fichiers modifiés, fixe la profondeur d’une revue avant qu’elle commence, compare une revue avec une précédente sans déclarer corrigée une remarque non vérifiée, et masque les identifiants dans ce qu’il écrit. Rien ne change dans l’installation ou la mise à jour. |
|
|
197
199
|
| 0.19.0 | 2026-09-27 | bmad-plus review scelle ce qu’une revue doit couvrir, retrouve chaque remarque par le code qu’elle cite, et déduit le verdict de la couverture plutôt que du nombre de remarques. Le tri des revues garde désormais une remarque tant qu’un motif cité ne la réfute pas. Rien ne change dans l’installation ou la mise à jour. |
|
|
198
|
-
| 0.18.0 | 2026-09-25 | La page de recette vérifie désormais chaque enregistrement, restaure vos réponses au rechargement avant toute autre chose, distingue les passages d’autres révisions et d’autres onglets, et nomme seize garanties que la construction refuse de perdre. Rien ne change dans l’installation ou la mise à jour ; reconstruisez vos pages de recette pour obtenir la nouvelle page. |
|
|
199
|
-
| 0.17.1 | 2026-09-24 | Installer par-dessus une autre version s’arrête désormais et renvoie vers update, une réinstallation conserve vos réglages, et les mises à jour retirent les fichiers qu’une version ne livre plus en gardant une sauvegarde restaurable. Certains comportements d’installation changent : vérifiez vos scripts avant de les relancer. |
|
|
200
200
|
|
|
201
201
|
[Historique des versions et guide de mise à jour](https://bmad-plus.rochetta.fr/fr/docs/#changelog) · [Toutes les versions publiées sur npm](https://www.npmjs.com/package/bmad-plus?activeTab=versions)
|
|
202
202
|
|
|
@@ -62,7 +62,7 @@ When auto-activating a role, **announce it**: "💡 I'm switching to [Role] mode
|
|
|
62
62
|
3. Verify each suspected issue before grouping findings. Trace its trigger through the actual caller and guards, inspect counterevidence, and reproduce it when practical. A failure in an unreachable state is not an established defect. Check every source, including a reviewer that describes its own findings as pre-verified.
|
|
63
63
|
4. Keep a compact finding record with identity, source, location, claimed consequence, evidence or refutation, disposition, relevant input identity and next action. The default disposition is keep: refute only on a quoted ground — the described construct is absent from the file, the code contradicts the claim (guard, caller or test quoted), or another entry already carries the same cause — and write the analysis before the disposition. A security, data-loss or money finding without such a quote stays unresolved. Use confirmed, refuted or unresolved; rank confirmed defects by impact and likelihood. Preserve previous entries when their disposition changes. Group confirmed findings only when the same cause explains them, retaining each source record. Do not merge away a refutation or impose a finding quota.
|
|
64
64
|
5. Inspect verification at the actual consumer. Read assertions and check how tests are selected before judging their coverage. Search relevant symbols and imports before asserting that coverage is absent. For a verification gap, name the consumer and a concrete regression or missed adoption that the current checks would fail to catch. Skipped tests, mocks that bypass the changed path and helper-only success do not prove that consumer works.
|
|
65
|
-
6. When the BMAD+ CLI is available, back a code review with its evidence: `bmad-plus review scope <id>` before reading, then `findings.json` with every finding quoting its code verbatim and `coverage.json` accounting for every selected file, then `bmad-plus review anchor <id>` and `bmad-plus review gate <id>`. Report the gate's disposition (incomplete, findings or clean) without upgrading it.
|
|
65
|
+
6. When the BMAD+ CLI is available, back a code review with its evidence: `bmad-plus review scope <id>` before reading (its `checklist.md` holds the review rules that apply to the changed paths, and `--effort` sets the passes), then `findings.json` with every finding quoting its code verbatim and `coverage.json` accounting for every selected file, then `bmad-plus review anchor <id>` and `bmad-plus review gate <id>`. Record in `coverage.json` how the session ended (`run.stop`), the passes actually run and every unit attempt; stop retrying a unit or rule group after three failures in a row, and never estimate tokens or time. Report the gate's disposition (incomplete, findings or clean) without upgrading it; a stopped review is never clean. To resume an interrupted review, `bmad-plus review continue <id>`: it refuses when the code or the rules moved. On a second review of the same work, `bmad-plus review compare <id> --since <earlier-id>`: a finding gone from a file this review did not complete is not reviewed, never fixed.
|
|
66
66
|
7. Reconcile acceptance using executed commands or direct observations against the current artifact set. Record passed, failed, skipped and unavailable checks separately. A missing required reviewer or untested criterion prevents a completed-acceptance claim, even when the remaining checks pass. A same-author review must not be described as independent verification.
|
|
67
67
|
|
|
68
68
|
## Repair and continuation
|
|
@@ -21,7 +21,17 @@ arbitrary branch. Read the intended behavior and applicable project constraints.
|
|
|
21
21
|
`bmad-plus review scope <id> --base <ref>` (or `--workspace` for uncommitted
|
|
22
22
|
work) writes `_bmad-output/review/<id>/scope.json` with every selected file,
|
|
23
23
|
every excluded file and its reason (secret, binary, deleted, generated), and
|
|
24
|
-
ordered review units. Never read or quote an excluded secret file.
|
|
24
|
+
ordered review units. Never read or quote an excluded secret file. Choose the
|
|
25
|
+
depth with `--effort low|medium|high` (one pass without refutation; two passes
|
|
26
|
+
with refutation, the default; three passes) and follow the `plan` the scope
|
|
27
|
+
prints: survey the whole change before reading when it says `planFirst`, and
|
|
28
|
+
review units in parallel when it says `parallelUnits`. Read `checklist.md`
|
|
29
|
+
beside the scope: it holds, once each, the review rules that apply to the
|
|
30
|
+
selected paths — built-in rules by language and file kind, plus the project's
|
|
31
|
+
own from `_bmad/review-rules.yaml`, which can add, replace or disable rules.
|
|
32
|
+
`bmad-plus review rules <path>` shows which rules a file gets. Each unit
|
|
33
|
+
lists its rule groups (`code`, `data`, `delivery` or the project's own):
|
|
34
|
+
parallel reviewers may split a unit by group. Inventory
|
|
25
35
|
related callers, tests and requirements. Preserve existing edits and record
|
|
26
36
|
unavailable context. A supplied diff may omit the surrounding behavior needed
|
|
27
37
|
to evaluate it.
|
|
@@ -63,7 +73,25 @@ arbitrary branch. Read the intended behavior and applicable project constraints.
|
|
|
63
73
|
and requote any finding it reports ambiguous or unlocated; then
|
|
64
74
|
`bmad-plus review gate <id>`. Report its disposition as it is: `incomplete`
|
|
65
75
|
when a selected file is unaccounted for or a finding is not anchored, `findings`
|
|
66
|
-
or `clean` otherwise. `clean` covers the reviewed scope only.
|
|
76
|
+
or `clean` otherwise. `clean` covers the reviewed scope only. A finding that
|
|
77
|
+
applies a checklist rule names it in `rule`; the CLI refuses a rule that does
|
|
78
|
+
not apply to that path. The anchored record replaces credential-like values
|
|
79
|
+
quoted in a finding with `[REDACTED]` and counts them. Record the session in
|
|
80
|
+
`coverage.json` under `run`: `stop` (`completed`, `budget`, `time-limit`,
|
|
81
|
+
`failure-streak` or `interrupted`, with a `detail` unless completed), the
|
|
82
|
+
`passes` actually run, every unit attempt in order (`unit`, the rule `group`
|
|
83
|
+
when reviewers split by group, `completed` or `failed` with a reason), and
|
|
84
|
+
tokens or duration only when the host reports them — never estimate them.
|
|
85
|
+
After three failed attempts in a row on the same unit or group, stop
|
|
86
|
+
retrying it: mark its files failed. A stopped review is never clean. In CI,
|
|
87
|
+
`bmad-plus review gate <id> --emit-check <file.json>` also writes the verdict
|
|
88
|
+
as a check result (`bmad-plus/review-check/1`, with a GitHub check-runs
|
|
89
|
+
payload); the exit code stays the verdict.
|
|
90
|
+
9. On a second review of the same work, compare it with the earlier one:
|
|
91
|
+
`bmad-plus review compare <id> --since <earlier-id>` writes `compare.json`
|
|
92
|
+
with each finding new, persisting, refuted, resolved or not reviewed. An
|
|
93
|
+
earlier finding counts as resolved only when this review completed its file;
|
|
94
|
+
otherwise it is not reviewed, never fixed. Renamed files are followed.
|
|
67
95
|
|
|
68
96
|
## Output and acceptance
|
|
69
97
|
|
|
@@ -79,7 +107,14 @@ or an untested requirement.
|
|
|
79
107
|
|
|
80
108
|
## Continue
|
|
81
109
|
|
|
82
|
-
|
|
83
|
-
|
|
110
|
+
With a sealed scope, run `bmad-plus review continue <id>` first. When the code,
|
|
111
|
+
its head ref or the review rules moved, it refuses: seal a new scope and compare
|
|
112
|
+
it with this one (step 9) instead of continuing. Otherwise `continue.json` lists
|
|
113
|
+
the units, files and rule groups still owed, the files abandoned after three
|
|
114
|
+
failures (they stay failed), the findings to requote and the passes left; add to
|
|
115
|
+
the same `coverage.json` and `findings.json` and record the new `run.stop`.
|
|
116
|
+
|
|
117
|
+
Without a sealed scope, compare the current diff and input hashes with the
|
|
118
|
+
reviewed snapshot. Preserve prior findings and check their resolution against actual changes. Re-review
|
|
84
119
|
affected behavior and invalidate conclusions that relied on changed inputs;
|
|
85
120
|
do not rerun unchanged checks merely to refresh the report date.
|
|
@@ -32,13 +32,14 @@ except ImportError:
|
|
|
32
32
|
)
|
|
33
33
|
sys.exit(1)
|
|
34
34
|
|
|
35
|
-
# Reuse the hardened SSRF guard from seo_fetch
|
|
35
|
+
# Reuse the hardened SSRF guard and pinned transport from seo_fetch
|
|
36
|
+
# (same package/directory).
|
|
36
37
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
37
38
|
try:
|
|
38
|
-
from seo_fetch import
|
|
39
|
+
from seo_fetch import ALLOWED_SCHEMES, UnsafeURLError, create_session
|
|
39
40
|
except ImportError:
|
|
40
41
|
print(
|
|
41
|
-
"Error: seo_fetch.
|
|
42
|
+
"Error: seo_fetch.create_session is required (SSRF protection). "
|
|
42
43
|
"Ensure seo_fetch.py is present alongside seo_crawl.py.",
|
|
43
44
|
file=sys.stderr,
|
|
44
45
|
)
|
|
@@ -65,6 +66,8 @@ USER_AGENT = (
|
|
|
65
66
|
"(KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 BMADSEOEngine/2.0"
|
|
66
67
|
)
|
|
67
68
|
|
|
69
|
+
MAX_REDIRECTS = 5
|
|
70
|
+
|
|
68
71
|
|
|
69
72
|
class SEOCrawler:
|
|
70
73
|
"""Recursive mini-crawler for SEO site structure analysis."""
|
|
@@ -82,6 +85,7 @@ class SEOCrawler:
|
|
|
82
85
|
self.sitemap_urls: list = []
|
|
83
86
|
self.robots_txt: Optional[str] = None
|
|
84
87
|
self.errors: list = []
|
|
88
|
+
self.session = create_session()
|
|
85
89
|
|
|
86
90
|
def normalize_url(self, url: str) -> str:
|
|
87
91
|
"""Normalize URL for deduplication."""
|
|
@@ -96,42 +100,50 @@ class SEOCrawler:
|
|
|
96
100
|
def _safe_get(self, url: str, error_prefix: str = "Blocked"):
|
|
97
101
|
"""GET a URL, following redirects manually with per-hop SSRF revalidation.
|
|
98
102
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
Every request goes through the pinned session from seo_fetch, which
|
|
104
|
+
validates the target and connects to the address it validated (no DNS
|
|
105
|
+
rebinding between check and connect). Redirects are followed with
|
|
106
|
+
allow_redirects=False so each hop is validated the same way: a public URL
|
|
107
|
+
that 302s to an internal/metadata endpoint (redirect-based SSRF) is
|
|
108
|
+
refused. Returns the final requests.Response, or None (with an entry
|
|
109
|
+
appended to self.errors) when a hop is unsafe or too many redirects
|
|
110
|
+
occur. Used by fetch(), fetch_robots_txt() and parse_sitemap() so every
|
|
111
|
+
network path shares the same guard.
|
|
105
112
|
"""
|
|
106
|
-
if not is_safe_url(url):
|
|
107
|
-
self.errors.append(
|
|
108
|
-
{"url": url, "error": f"{error_prefix}: private/internal URL (SSRF protection)"}
|
|
109
|
-
)
|
|
110
|
-
return None
|
|
111
113
|
current_url = url
|
|
112
114
|
hops = 0
|
|
113
115
|
while True:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
try:
|
|
117
|
+
response = self.session.get(
|
|
118
|
+
current_url,
|
|
119
|
+
headers={"User-Agent": USER_AGENT},
|
|
120
|
+
timeout=self.timeout,
|
|
121
|
+
allow_redirects=False,
|
|
122
|
+
)
|
|
123
|
+
except UnsafeURLError as e:
|
|
124
|
+
prefix = error_prefix if current_url == url else f"{error_prefix} redirect"
|
|
125
|
+
self.errors.append(
|
|
126
|
+
{"url": current_url, "error": f"{prefix}: {e} (SSRF protection)"}
|
|
127
|
+
)
|
|
128
|
+
return None
|
|
120
129
|
if not response.is_redirect:
|
|
121
130
|
return response
|
|
122
131
|
location = response.headers.get("Location")
|
|
123
132
|
if not location:
|
|
124
133
|
return response
|
|
134
|
+
response.close()
|
|
125
135
|
next_url = urljoin(current_url, location)
|
|
126
|
-
if urlparse(next_url).scheme not in
|
|
136
|
+
if urlparse(next_url).scheme not in ALLOWED_SCHEMES:
|
|
127
137
|
self.errors.append(
|
|
128
138
|
{"url": next_url,
|
|
129
|
-
"error": f"{error_prefix} redirect: non-HTTP(S)
|
|
139
|
+
"error": f"{error_prefix} redirect: non-HTTP(S) URL (SSRF protection)"}
|
|
130
140
|
)
|
|
131
141
|
return None
|
|
132
142
|
hops += 1
|
|
133
|
-
if hops >
|
|
134
|
-
self.errors.append(
|
|
143
|
+
if hops > MAX_REDIRECTS:
|
|
144
|
+
self.errors.append(
|
|
145
|
+
{"url": current_url, "error": f"Too many redirects (max {MAX_REDIRECTS})"}
|
|
146
|
+
)
|
|
135
147
|
return None
|
|
136
148
|
current_url = next_url
|
|
137
149
|
|