Skip to content

Commit 23e2aa6

Browse files
romanlutzCopilot
andauthored
DOC: Enable --strict on docs build, fix converter anchors + broken internal refs (closes #1741) (#1745)
Co-authored-by: romanlutz <romanlutz@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 1f962ae commit 23e2aa6

25 files changed

Lines changed: 88 additions & 353 deletions

.pre-commit-config.yaml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,6 @@ repos:
6969
name: Ruff (Jupyter Notebooks)
7070
args: [--fix]
7171

72-
- repo: local
73-
hooks:
74-
- id: check-links
75-
name: Check Links in Python and md Files
76-
entry: python ./build_scripts/check_links.py
77-
language: python
78-
files: ^doc.*\.(py|md)$
79-
additional_dependencies: ['requests']
80-
exclude: (release_process.md|git.md|^doc/deployment/|tests|pyrit/prompt_converter/morse_converter.py|.github|pyrit/prompt_converter/emoji_converter.py|pyrit/score/markdown_injection.py|^pyrit/datasets/|^pyrit/auxiliary_attacks/gcg/)
81-
8272
- repo: https://github.com/allganize/ty-pre-commit
8373
rev: v0.0.32
8474
hooks:

Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ ty:
2525
docs-build:
2626
uv run python build_scripts/pydoc2json.py pyrit --submodules -o doc/_api/pyrit_all.json
2727
uv run python build_scripts/gen_api_md.py
28-
cd doc && uv run jupyter-book build --all --html
28+
# --strict validates URLs and cross-refs; skips are configured in doc/myst.yml under error_rules
29+
cd doc && uv run jupyter-book build --all --html --strict
2930
uv run ./build_scripts/generate_rss.py
3031

3132
# Build the full documentation site including the PDF export.
@@ -36,7 +37,8 @@ docs-build:
3637
docs-build-all:
3738
uv run python build_scripts/pydoc2json.py pyrit --submodules -o doc/_api/pyrit_all.json
3839
uv run python build_scripts/gen_api_md.py
39-
cd doc && uv run jupyter-book build --all --html --pdf
40+
# --strict validates URLs and cross-refs; skips are configured in doc/myst.yml under error_rules
41+
cd doc && uv run jupyter-book build --all --html --pdf --strict
4042
uv run ./build_scripts/generate_rss.py
4143

4244
# Regenerate only the API reference pages (without building the full site)

build_scripts/check_links.py

Lines changed: 0 additions & 208 deletions
This file was deleted.

doc/blog/2025_01_27.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,11 @@ Finally, when PyRIT gets a response from the Target LLM, it switches to another
7878

7979
When examining this request, you may discover that occasionally the Adversarial LLM struggles with generating the right JSON format, leading to an error in PyRIT, regardless of whether the objective was achieved or not. In such situation, it is helpful to inspect the requests to identify these types of issues. Specifically, I found a problem when the LLM response contained double quotes, causing issues with subsequent JSON formats which was fixed using the "SearchReplaceConverter"[^9] prompt converter.
8080

81-
[^7]: "Multi-Turn Attack - RedTeamingAttack Example", https://microsoft.github.io/PyRIT/code/executor/attack/2_red_teaming_attack.html
81+
[^7]: "Multi-Turn Attack - RedTeamingAttack Example", ../code/executor/attack/2_red_teaming_attack.ipynb
8282

83-
[^8]: "PyRIT - SearchReplaceConverter", https://microsoft.github.io/PyRIT/_autosummary/pyrit.prompt_converter.SearchReplaceConverter.html
83+
[^8]: "PyRIT - SearchReplaceConverter", ../api/pyrit_prompt_converter.md#searchreplaceconverter
8484

85-
[^9]: "PyRIT - True False Scoring", https://microsoft.github.io/PyRIT/code/scoring/2_true_false_scorers.html#true-false-scoring
85+
[^9]: "PyRIT - True False Scoring", ../code/scoring/2_true_false_scorers.ipynb#true-false-scoring
8686

8787
### Final Thoughts
8888

doc/blog/2025_02_11.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ See the updated documentation [here](../code/datasets/1_loading_datasets.ipynb).
3232

3333
## What else can we do with this?
3434

35-
Now that we've loaded our dataset into PyRIT as a `SeedPromptDataset` the really exciting red teaming can begin. A great example of this is in our [Baseline-Only Execution](../code/scenarios/9_baseline_only.ipynb) notebook! We can use the prompts to evaluate the target by sending all the previously loaded prompts, modifying which attacks to use, and storing the scores for further analysis.
35+
Now that we've loaded our dataset into PyRIT as a `SeedPromptDataset` the really exciting red teaming can begin. A great example of this is the [Baseline Execution](../code/scenarios/0_scenarios.ipynb#baseline-execution) section of our scenarios overview! We can use the prompts to evaluate the target by sending all the previously loaded prompts, modifying which attacks to use, and storing the scores for further analysis.
3636

3737
In this blog post, we've walked through how we use structured datasets through our `SeedPrompt` and `SeedPromptDataset` classes. PyRIT's architecture allows for customization at every stage - whether through converters or configuring different scorers - and seed prompts set us up to effectively probe for risks in AI systems. Send over any contributions to add more datasets, refine seed prompts, or any open issues on Github! Now that you understand a core component of PyRIT, go ahead and try it out!

doc/blog/2025_06_06.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The [AI Recruiter](https://github.com/KutalVolkan/ai_recruiter) is designed to m
1212

1313
- Résumé Processing & Semantic Matching: Résumés are extracted from PDFs, with embeddings generated using models like text-embedding-ada-002. These embeddings enable semantic matching, while GPT-4o is later used to assign a match score based on relevance and extracted content.
1414

15-
- Automated RAG Vulnerability Testing: Attackers can manipulate résumé content by injecting hidden text (via a [PDF converter](https://github.com/microsoft/PyRIT/blob/main/doc/code/converters/pdf_converter.ipynb)) that optimizes scoring, influencing the AI Recruiter’s ranking system.
15+
- Automated RAG Vulnerability Testing: Attackers can manipulate résumé content by injecting hidden text (via a [PDF converter](../code/converters/5_file_converters.ipynb#pdfconverter)) that optimizes scoring, influencing the AI Recruiter’s ranking system.
1616

1717
- [XPIA Attack](https://github.com/microsoft/PyRIT/blob/main/doc/code/executor/workflow/2_xpia_ai_recruiter.ipynb) Integration: PyRIT enables full automation of prompt injections, making AI vulnerability research efficient and reproducible.
1818
---

doc/blog/2026_04_14_scoring_scorers.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ flowchart TB
108108

109109
There are a few different ways to view metrics for specific scoring configurations.
110110

111-
**Directly on a scorer instance:** Call `get_scorer_metrics()` on any scorer object to look up its saved metrics (if they exist), as described at the bottom of the [Scorer Evaluation Identifier](#scorer-evaluation-identifier) section above. See the [scorer metrics notebook](../code/scoring/8_scorer_metrics.ipynb) to try it yourself!
111+
**Directly on a scorer instance:** Call `get_scorer_metrics()` on any scorer object to look up its saved metrics (if they exist), as described at the bottom of the [Scorer Evaluation Identifier](#scorer-evaluation-identifier) section above. See the [scorer metrics notebook](../code/scoring/7_scorer_metrics.ipynb) to try it yourself!
112112

113113
**Automatically in scenario output:** When running scenarios and printing results (i.e., in [pyrit_scan](../scanner/1_pyrit_scan.ipynb) or [pyrit_shell](../scanner/2_pyrit_shell.md)), metrics are automatically fetched and displayed alongside the attack results (as long as the scoring configuration has been evaluated before):
114114

@@ -132,7 +132,7 @@ The framework checks the JSONL registry for an existing entry matching the score
132132

133133
![alt text](2026_04_14_running_evaluation.png)
134134

135-
For the full walkthrough — including running objective and harm evaluations, configuring custom datasets, and comparing results — give the [scorer metrics notebook](../code/scoring/8_scorer_metrics.ipynb) a try!
135+
For the full walkthrough — including running objective and harm evaluations, configuring custom datasets, and comparing results — give the [scorer metrics notebook](../code/scoring/7_scorer_metrics.ipynb) a try!
136136

137137
## Closing Thoughts
138138

doc/code/converters/1_text_to_text_converters.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"id": "1",
2323
"metadata": {},
2424
"source": [
25-
"<a id=\"non-llm-converters\"></a>\n",
25+
"(non-llm-converters)=\n",
2626
"## Non-LLM Converters\n",
2727
"\n",
2828
"Non-LLM converters use deterministic algorithms to transform text. These include:\n",
@@ -454,7 +454,7 @@
454454
"id": "10",
455455
"metadata": {},
456456
"source": [
457-
"<a id=\"llm-based-converters\"></a>\n",
457+
"(llm-based-converters)=\n",
458458
"## LLM-Based Converters\n",
459459
"\n",
460460
"LLM-based converters use language models to transform prompts. These converters are more flexible and can produce more natural variations, but they are slower and require an LLM target.\n",

doc/code/converters/1_text_to_text_converters.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
# - **[LLM-Based Converters](#llm-based-converters)**: AI-powered transformations including translation, variation, and semantic modifications
2323

2424
# %% [markdown]
25-
# <a id="non-llm-converters"></a>
25+
# (non-llm-converters)=
2626
# ## Non-LLM Converters
2727
#
2828
# Non-LLM converters use deterministic algorithms to transform text. These include:
@@ -225,7 +225,7 @@
225225
print("Variation Selector:", await var_selector.convert_async(prompt=prompt)) # type: ignore
226226

227227
# %% [markdown]
228-
# <a id="llm-based-converters"></a>
228+
# (llm-based-converters)=
229229
# ## LLM-Based Converters
230230
#
231231
# LLM-based converters use language models to transform prompts. These converters are more flexible and can produce more natural variations, but they are slower and require an LLM target.

doc/code/converters/2_audio_converters.ipynb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"id": "1",
2424
"metadata": {},
2525
"source": [
26-
"<a id=\"text-to-audio\"></a>\n",
26+
"(text-to-audio)=\n",
2727
"## Text to Audio\n",
2828
"\n",
2929
"The `AzureSpeechTextToAudioConverter` converts text input into audio output, generating spoken audio files."
@@ -72,7 +72,7 @@
7272
"id": "3",
7373
"metadata": {},
7474
"source": [
75-
"<a id=\"audio-to-text\"></a>\n",
75+
"(audio-to-text)=\n",
7676
"## Audio to Text\n",
7777
"\n",
7878
"The `AzureSpeechAudioToTextConverter` transcribes audio files into text. Below we use the audio file created in the previous section."
@@ -117,7 +117,7 @@
117117
"id": "5",
118118
"metadata": {},
119119
"source": [
120-
"<a id=\"audio-to-audio\"></a>\n",
120+
"(audio-to-audio)=\n",
121121
"## Audio to Audio\n",
122122
"\n",
123123
"Audio-to-audio converters modify existing audio files. All of these converters accept `audio_path` input\n",
@@ -240,7 +240,8 @@
240240
],
241241
"metadata": {
242242
"jupytext": {
243-
"cell_metadata_filter": "-all"
243+
"cell_metadata_filter": "-all",
244+
"main_language": "python"
244245
},
245246
"language_info": {
246247
"codemirror_mode": {

0 commit comments

Comments
 (0)