Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ jobs:

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for per-page last-updated dates

# We build doxygen from source because of
# https://github.com/doxygen/doxygen/issues/9016
Expand Down Expand Up @@ -51,20 +53,14 @@ jobs:
base-url-path: https://mflowcode.github.io/
path-to-root: build/install/docs/mfc
include-pdf: false
sitemap-format: txt
sitemap-format: xml

- name: Output stats
run: |
echo "sitemap-path = ${{ steps.sitemap.outputs.sitemap-path }}"
echo "url-count = ${{ steps.sitemap.outputs.url-count }}"
echo "excluded-count = ${{ steps.sitemap.outputs.excluded-count }}"

- name: Linkcheck - Lychee
uses: lycheeverse/lychee-action@v2
with:
args: -c .lychee.toml build/install/docs/mfc/
fail: false

- name: Publish Documentation
if: github.repository == 'MFlowCode/MFC' && github.ref == 'refs/heads/master' && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' )
run: |
Expand All @@ -81,5 +77,11 @@ jobs:
git -C ../www commit -m "Docs @ ${GITHUB_SHA::7}" || true
git -C ../www push

- name: Linkcheck - Lychee
uses: lycheeverse/lychee-action@v2
with:
args: -c .lychee.toml build/install/docs/mfc/
fail: true
Comment on lines +80 to +84
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Lychee now runs after publish — broken links won't block deployment on scheduled/dispatch runs.

Moving Lychee after the Publish step (with fail: true) means that on schedule / workflow_dispatch triggers, documentation is deployed to GitHub Pages before link checking occurs. A link-check failure will mark the workflow as failed but won't roll back the published content.

On PRs this is not an issue (the publish step is skipped), so Lychee correctly gates PR merges. For production runs, this trade-off appears intentional per the PR description ("move publish step before lychee"), but it's worth confirming that alerting-on-failure (e.g., via GitHub notification or branch protection) is sufficient to catch post-deploy regressions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/docs.yml around lines 80 - 84, The Linkcheck step
("Linkcheck - Lychee" using lycheeverse/lychee-action@v2 with fail: true) is
placed after the Publish step so broken links won't prevent deployment on
schedule/workflow_dispatch runs; move the Lychee step earlier in the job
sequence so it runs (and can fail) before the Publish step, or alternatively
ensure the Publish step is conditional on the Linkcheck step succeeding (e.g.,
make Publish depend on the Linkcheck job/result) so that fail: true actually
blocks deployment for non-PR runs.


# DOC_PUSH_URL should be of the format:
# --> https://<username>:<token>@github.com/<username>/<repository>
10 changes: 8 additions & 2 deletions .lychee.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,11 @@ accept = ["200", "429"]

verbose = "error"

# Exclude sitemap from link checking (it contains pre-publish production URLs)
exclude_path = ["**/sitemap.txt"]
# Exclude sitemap file from scanning (it contains pre-publish production URLs)
exclude_path = ["sitemap\\.xml"]

# Exclude URLs that fail due to external issues (broken SSL, pre-deploy only, etc.)
exclude = [
"https://mflowcode\\.github\\.io/sitemap\\.xml", # Only exists after deployment
"https://cpe\\.ext\\.hpe\\.com", # HPE Cray docs have broken SSL cert
]
19 changes: 19 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,25 @@ if (MFC_DOCUMENTATION)
GEN_DOCS(post_process "MFC: Post-Process")
GEN_DOCS(documentation "MFC")

# Inject per-page last-updated dates into documentation markdown files.
# Runs after auto-generated .md files exist, before Doxygen processes them.
# Uses a stamp file so it only runs once per build.
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/inject-dates.stamp"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/examples.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/case_constraints.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/physics_constraints.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/cli-reference.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/parameters.md"
Comment on lines +814 to +818
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The custom command dependency list in CMakeLists.txt includes the generated markdown files that the script is supposed to modify. This creates a circular dependency issue: the script modifies these files, which are listed as dependencies, which would trigger the script to run again. The stamp file approach helps, but the dependencies should be the script itself and the files it reads from, not the files it writes to.

Suggested change
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/examples.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/case_constraints.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/physics_constraints.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/cli-reference.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/parameters.md"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/docs/inject-dates.py"

Copilot uses AI. Check for mistakes.
Comment on lines +814 to +818
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The inject-dates custom command runs docs/inject-dates.py but doesn’t list that script in DEPENDS, so updates to the script won’t retrigger the stamp and documentation can go stale without a clean build.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At CMakeLists.txt, line 814:

<comment>The inject-dates custom command runs docs/inject-dates.py but doesn’t list that script in DEPENDS, so updates to the script won’t retrigger the stamp and documentation can go stale without a clean build.</comment>

<file context>
@@ -806,6 +806,24 @@ if (MFC_DOCUMENTATION)
+    # Uses a stamp file so it only runs once per build.
+    add_custom_command(
+        OUTPUT  "${CMAKE_CURRENT_BINARY_DIR}/inject-dates.stamp"
+        DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/examples.md"
+                "${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/case_constraints.md"
+                "${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/physics_constraints.md"
</file context>
Suggested change
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/examples.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/case_constraints.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/physics_constraints.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/cli-reference.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/parameters.md"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/examples.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/case_constraints.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/physics_constraints.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/cli-reference.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/parameters.md"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/inject-dates.py"

COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/docs/inject-dates.py"
"${CMAKE_CURRENT_SOURCE_DIR}"
COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_BINARY_DIR}/inject-dates.stamp"
COMMENT "Injecting page dates into documentation"
VERBATIM
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Add VERBATIM to the new custom command so that the Python invocation and paths are safely quoted across platforms, matching the other custom commands in this file. [custom_rule]

Severity Level: Minor ⚠️

Suggested change
)
VERBATIM
Why it matters? ⭐

Adding VERBATIM matches the pattern used elsewhere in this CMakeLists (other add_custom_command invocations include VERBATIM) and ensures CMake does not perform platform-specific tokenization/escaping on the Python command and its arguments. This improves robustness/portability of the custom command and directly addresses a portability/consistency concern in the diff. The change is syntactically valid CMake and fixes a real potential issue rather than being purely cosmetic.

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** CMakeLists.txt
**Line:** 823:823
**Comment:**
	*Custom Rule: Add VERBATIM to the new custom command so that the Python invocation and paths are safely quoted across platforms, matching the other custom commands in this file.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

add_custom_target(inject_page_dates DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/inject-dates.stamp")
add_dependencies(documentation_doxygen inject_page_dates)
Comment on lines +825 to +826
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inject_page_dates target is added as a dependency of documentation_doxygen, but the correct ordering might need verification. The script should run after the markdown files are generated (which happens as part of documentation_doxygen's dependencies) but before Doxygen processes them. The current setup may not guarantee this ordering. Consider making inject_page_dates depend on the commands that generate the markdown files, and having documentation_doxygen depend on inject_page_dates.

Copilot uses AI. Check for mistakes.

# > Copy Resources (main landing page & assets)
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/docs/res"
DESTINATION "docs/mfc")
Expand Down
3 changes: 2 additions & 1 deletion docs/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<meta name=”keywords” content="exascale, fluid dynamics, cfd, computational fluid dynamics, compressible, hpc, bryngelson, colonius, subgrid, multiphase, frontier, summit, el capitan, aurora, amd gpu, gpu, nvidia"/>
<meta name="description" content="$title — MFC documentation. Open-source exascale multiphase flow solver." />
<meta name="keywords" content="exascale, fluid dynamics, cfd, computational fluid dynamics, compressible, hpc, bryngelson, colonius, subgrid, multiphase, frontier, summit, el capitan, aurora, amd gpu, gpu, nvidia"/>
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
Expand Down
62 changes: 48 additions & 14 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,54 @@
<meta property="og:url" content="https://mflowcode.github.io" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareSourceCode",
"name": "MFC",
"alternateName": "Multi-Component Flow Code",
"description": "Open-source exascale multiphase flow solver. 2025 Gordon Bell Prize Finalist. Scales to 200+ trillion grid points on 43,000+ GPUs.",
"url": "https://mflowcode.github.io",
"license": "https://opensource.org/licenses/MIT",
"programmingLanguage": ["Fortran", "Python"],
"codeRepository": "https://github.com/MFlowCode/MFC",
"author": {
"@type": "Organization",
"name": "MFlowCode",
"url": "https://github.com/MFlowCode"
},
"award": "2025 ACM Gordon Bell Prize Finalist"
}
</script>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="icon" type="image/x-icon" href="res/icon.ico">
<script>
const sims = [
{ name: "Viscous Taylor-Green vortex", image: "res/simulations/h.png", computer: "Delta", accelerators: "128 A100s", walltime: "17h", source: "https://www.youtube.com/watch?v=7i2h08dlDQw" },
{ name: "Shedding water droplet", image: "res/simulations/a.png", computer: "Summit", accelerators: "960 V100s", walltime: "4h", source: "https://www.youtube.com/watch?v=Gjj-qZkXcrg" },
{ name: "Flow over an airfoil (vorticity)", image: "res/simulations/g.png", computer: "Delta", accelerators: "128 A100s", walltime: "19h", source: "https://www.youtube.com/watch?v=FvAgnBW59cY" },
{ name: "Cavitation fragments kidney stone", image: "res/simulations/d.png", computer: "Summit", accelerators: "576 V100s", walltime: "30 min", source: "https://doi.org/10.48550/arXiv.2305.09163" },
{ name: "Breakup of vibrated interface", image: "res/simulations/f.png", computer: "Summit", accelerators: "128 V100s", walltime: "4h", source: "https://www.youtube.com/watch?v=XQ3g1oSg8mc" },
{ name: "Mach 2 flow over a sphere", image: "res/simulations/i.png", computer: "Phoenix", accelerators: "36 V100s", walltime: "30m", source: "https://www.youtube.com/watch?v=HQGSUvYEGqM" },
{ name: "Mach 2 shear layer", image: "res/simulations/j.png", computer: "Phoenix", accelerators: "32 V100s", walltime: "15m", source: "https://www.youtube.com/watch?v=GtcdCHLmJO8" },
{ name: "Collapsing bubbles (pressure)", image: "res/simulations/b.png", computer: "Summit", accelerators: "216 V100s", walltime: "3h", source: "https://doi.org/10.48550/arXiv.2305.09163" },
{ name: "Collapsing bubbles (streamlines)", image: "res/simulations/c.png", computer: "Summit", accelerators: "216 V100s", walltime: "3h", source: "https://doi.org/10.48550/arXiv.2305.09163" },
// Rockets & jets
{ name: "Mach 12 Starship Super Heavy", image: "res/simulations/o.png", computer: "Alps", computerUrl: "https://www.cscs.ch/computers/alps/", accelerators: "5K GH200s", walltime: "18h", source: "https://www.youtube.com/watch?v=NSn3OVF8N4I" },
{ name: "Mach 10 triple jet booster", image: "res/simulations/n.png", computer: "Frontier", computerUrl: "https://www.olcf.ornl.gov/frontier/", accelerators: "10K GCDs", walltime: "12h", source: "https://www.youtube.com/watch?v=pMUl55xqGgM" },
{ name: "Mach 2 flow over a sphere", image: "res/simulations/i.png", computer: "Phoenix", computerUrl: "https://www.pace.gatech.edu/", accelerators: "36 V100s", walltime: "30m", source: "https://www.youtube.com/watch?v=HQGSUvYEGqM" },
{ name: "Mach 2 shear layer", image: "res/simulations/j.png", computer: "Phoenix", computerUrl: "https://www.pace.gatech.edu/", accelerators: "32 V100s", walltime: "15m", source: "https://www.youtube.com/watch?v=GtcdCHLmJO8" },
// Aerodynamics
{ name: "Flow over an airfoil (vorticity)", image: "res/simulations/g.png", computer: "Delta", computerUrl: "https://www.ncsa.illinois.edu/research/project-highlights/delta/", accelerators: "128 A100s", walltime: "19h", source: "https://www.youtube.com/watch?v=FvAgnBW59cY" },
{ name: "Pitching airfoil (3D)", image: "res/simulations/m.png", computer: "Phoenix", computerUrl: "https://www.pace.gatech.edu/", accelerators: "1 A100", walltime: "5h", source: "https://www.youtube.com/watch?v=2XH-9MumDHU" },
// Shock-droplet
{ name: "Shedding water droplet", image: "res/simulations/a.png", computer: "Summit", computerUrl: "https://www.olcf.ornl.gov/summit/", accelerators: "960 V100s", walltime: "4h", source: "https://www.youtube.com/watch?v=Gjj-qZkXcrg" },
// Biomedical & acoustics
{ name: "Burstwave lithotripsy", image: "res/simulations/k.png", computer: "Delta", computerUrl: "https://www.ncsa.illinois.edu/research/project-highlights/delta/", accelerators: "128 A100s", walltime: "30m", source: "https://www.youtube.com/watch?v=XWsUTaJXGF8" },
{ name: "Cavitation fragments kidney stone", image: "res/simulations/d.png", computer: "Summit", computerUrl: "https://www.olcf.ornl.gov/summit/", accelerators: "576 V100s", walltime: "30m", source: "https://doi.org/10.48550/arXiv.2305.09163" },
{ name: "Kidney stone stress waves", image: "res/simulations/l.png", computer: "Bridges2", computerUrl: "https://www.psc.edu/resources/bridges-2/", accelerators: "8 V100s", walltime: "20m", source: "https://www.youtube.com/watch?v=Q2L0J68qnRw" },
{ name: "Whale bubble net feeding", image: "res/simulations/p.png", computer: "Delta", computerUrl: "https://www.ncsa.illinois.edu/research/project-highlights/delta/", accelerators: "128 A100s", walltime: "30m", source: "https://www.youtube.com/watch?v=6EpP6tdCZSA" },
{ name: "Earplug acoustics (kinetic energy)", image: "res/simulations/q.png", computer: "Delta", computerUrl: "https://www.ncsa.illinois.edu/research/project-highlights/delta/", accelerators: "8 A100s", walltime: "5h", source: "https://www.youtube.com/watch?v=xSW5wZkdbrc" },
{ name: "Circular orifice (1 kHz)", image: "res/simulations/r.png", computer: "Delta", computerUrl: "https://www.ncsa.illinois.edu/research/project-highlights/delta/", accelerators: "16 A100s", walltime: "5h", source: "https://www.youtube.com/watch?v=jOhJ_c7eco4" },
// Bubble dynamics
{ name: "Collapsing bubbles (pressure)", image: "res/simulations/b.png", computer: "Summit", computerUrl: "https://www.olcf.ornl.gov/summit/", accelerators: "216 V100s", walltime: "3h", source: "https://doi.org/10.48550/arXiv.2305.09163" },
{ name: "Collapsing bubbles (streamlines)", image: "res/simulations/c.png", computer: "Summit", computerUrl: "https://www.olcf.ornl.gov/summit/", accelerators: "216 V100s", walltime: "3h", source: "https://doi.org/10.48550/arXiv.2305.09163" },
{ name: "Euler-Lagrange particle cloud", image: "res/simulations/s.png", computer: "Phoenix", computerUrl: "https://www.pace.gatech.edu/", accelerators: "8 A100s", walltime: "<1h", source: "https://www.youtube.com/watch?v=RoT-yC5Lxmg" },
// Fundamentals
{ name: "Breakup of vibrated interface", image: "res/simulations/f.png", computer: "Summit", computerUrl: "https://www.olcf.ornl.gov/summit/", accelerators: "128 V100s", walltime: "4h", source: "https://www.youtube.com/watch?v=XQ3g1oSg8mc" },
{ name: "Viscous Taylor-Green vortex", image: "res/simulations/h.png", computer: "Delta", computerUrl: "https://www.ncsa.illinois.edu/research/project-highlights/delta/", accelerators: "128 A100s", walltime: "17h", source: "https://www.youtube.com/watch?v=7i2h08dlDQw" },
];

const scalings = [
Expand All @@ -54,14 +88,14 @@
<img class="h-10" src="res/logo.png" alt="">
</div>
<div class="flex-1 p-2 font-semibold text-center">${s.name}</div>
<a class="w-10 text-center" href="${s.source}">
<i class="fa-solid fa-arrow-up-right-from-square"></i>
<a class="w-10 text-center text-xl" href="${s.source}" target="_blank">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Add rel="noopener noreferrer" to the external link opened with target="_blank" to prevent window.opener security risks.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/index.html, line 93:

<comment>Add rel="noopener noreferrer" to the external link opened with target="_blank" to prevent window.opener security risks.</comment>

<file context>
@@ -54,14 +90,14 @@
                         <div class="flex-1 p-2 font-semibold text-center">${s.name}</div>
-                        <a class="w-10 text-center" href="${s.source}">
-                            <i class="fa-solid fa-arrow-up-right-from-square"></i>
+                        <a class="w-10 text-center text-xl" href="${s.source}" target="_blank">
+                            <i class="${s.source.includes('youtube.com') ? 'fa-brands fa-youtube' : 'fa-solid fa-arrow-up-right-from-square'}"></i>
                         </a>
</file context>
Suggested change
<a class="w-10 text-center text-xl" href="${s.source}" target="_blank">
<a class="w-10 text-center text-xl" href="${s.source}" target="_blank" rel="noopener noreferrer">

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Using target="_blank" on external links without rel="noopener noreferrer" allows the opened page to access window.opener and potentially redirect the original page (reverse tabnabbing), so the link to simulation sources should include rel attributes to prevent this. [security]

Severity Level: Major ⚠️
- CRITICAL Docs homepage simulation links expose window.opener reference.
- WARN Original docs tab can be navigated by external site.
- WARN Security hardening for primary marketing page is reduced.
Suggested change
<a class="w-10 text-center text-xl" href="${s.source}" target="_blank">
<a class="w-10 text-center text-xl" href="${s.source}" target="_blank" rel="noopener noreferrer">
Steps of Reproduction ✅
1. Open `docs/index.html` in a browser (homepage entry point).

2. On DOMContentLoaded, script block at `docs/index.html:82-99` populates `#ft-sim` with
cards, rendering anchor at `docs/index.html:93` as `<a ... href="${s.source}"
target="_blank">` without `rel`.

3. Click any simulation source link (e.g., a YouTube or DOI URL) so it opens in a new tab
due to `target="_blank"`.

4. In the DevTools console of the newly opened tab, execute `window.opener.location =
'https://example.com'` and observe the original `docs/index.html` tab is navigated away,
demonstrating the reverse‑tabnabbing risk caused by missing `rel="noopener noreferrer"`.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** docs/index.html
**Line:** 93:93
**Comment:**
	*Security: Using target="_blank" on external links without rel="noopener noreferrer" allows the opened page to access window.opener and potentially redirect the original page (reverse tabnabbing), so the link to simulation sources should include rel attributes to prevent this.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Add a rel attribute to the external link opened in a new tab to prevent the new page from accessing the opener context. [custom_rule]

Severity Level: Minor ⚠️

Suggested change
<a class="w-10 text-center text-xl" href="${s.source}" target="_blank">
<a class="w-10 text-center text-xl" href="${s.source}" target="_blank" rel="noopener noreferrer">
Why it matters? ⭐

Adding rel="noopener noreferrer" mitigates reverse tabnabbing and prevents the opened page from accessing window.opener. This is a security best-practice for links using target="_blank" and directly improves the code's safety without changing behavior for legitimate destinations.

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** docs/index.html
**Line:** 93:93
**Comment:**
	*Custom Rule: Add a rel attribute to the external link opened in a new tab to prevent the new page from accessing the opener context.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

<i class="${s.source.includes('youtube.com') ? 'fa-brands fa-youtube' : 'fa-solid fa-arrow-up-right-from-square'}"></i>
Comment on lines +91 to +92
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add rel="noopener noreferrer" to all target="_blank" links

Both the source icon link (line 93) and the computer URL link (line 100) open a new tab without rel="noopener noreferrer". This leaves window.opener accessible in the opened tab and leaks the Referer header. These are straightforward to fix:

🔒 Proposed fix
-                        <a class="w-10 text-center text-xl" href="${s.source}" target="_blank">
+                        <a class="w-10 text-center text-xl" href="${s.source}" target="_blank" rel="noopener noreferrer">
-                            <div class="flex-1 text-center">${s.computerUrl ? `<a href="${s.computerUrl}" class="underline hover:text-amber-400" target="_blank">${s.computer}</a>` : s.computer}</div>
+                            <div class="flex-1 text-center">${s.computerUrl ? `<a href="${s.computerUrl}" class="underline hover:text-amber-400" target="_blank" rel="noopener noreferrer">${s.computer}</a>` : s.computer}</div>

Also applies to: 100-100

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/index.html` around lines 93 - 94, The anchor element rendering the
source icon (the <a class="w-10 text-center text-xl" href="${s.source}"
target="_blank"> element) and any other anchors that open new tabs should
include rel="noopener noreferrer"; update the JSX/HTML that generates this link
(and the computer URL link) to add rel="noopener noreferrer" whenever
target="_blank" is used so window.opener is not exposed and the referrer is not
leaked.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Guard the use of the includes method on the source URL to avoid runtime errors if the field is ever missing or null. [custom_rule]

Severity Level: Minor ⚠️

Suggested change
<i class="${s.source.includes('youtube.com') ? 'fa-brands fa-youtube' : 'fa-solid fa-arrow-up-right-from-square'}"></i>
<i class="${s.source && s.source.includes('youtube.com') ? 'fa-brands fa-youtube' : 'fa-solid fa-arrow-up-right-from-square'}"></i>
Why it matters? ⭐

The proposed change (s.source && s.source.includes(...)) guards against a potential runtime TypeError if a future sims entry omitted source or set it to null/undefined. This is a correctness improvement (runtime-safety) rather than cosmetic, and the improved code is a small, syntactically valid defensive check that directly resolves that issue.

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** docs/index.html
**Line:** 94:94
**Comment:**
	*Custom Rule: Guard the use of the `includes` method on the source URL to avoid runtime errors if the field is ever missing or null.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

</a>
Comment on lines +91 to 93
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Source-link icon has no accessible label — screen readers cannot identify the link.

The <a> contains only a FontAwesome <i> icon with no visible text, aria-label, or title. Screen-reader users will hear an unlabelled link.

♿ Proposed fix
-                        <a class="w-10 text-center text-xl" href="${s.source}" target="_blank">
-                            <i class="${s.source.includes('youtube.com') ? 'fa-brands fa-youtube' : 'fa-solid fa-arrow-up-right-from-square'}"></i>
+                        <a class="w-10 text-center text-xl" href="${s.source}" target="_blank" rel="noopener noreferrer"
+                           aria-label="${s.source.includes('youtube.com') ? 'Watch on YouTube' : 'View source'}">
+                            <i class="${s.source.includes('youtube.com') ? 'fa-brands fa-youtube' : 'fa-solid fa-arrow-up-right-from-square'}" aria-hidden="true"></i>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<a class="w-10 text-center text-xl" href="${s.source}" target="_blank">
<i class="${s.source.includes('youtube.com') ? 'fa-brands fa-youtube' : 'fa-solid fa-arrow-up-right-from-square'}"></i>
</a>
<a class="w-10 text-center text-xl" href="${s.source}" target="_blank" rel="noopener noreferrer"
aria-label="${s.source.includes('youtube.com') ? 'Watch on YouTube' : 'View source'}">
<i class="${s.source.includes('youtube.com') ? 'fa-brands fa-youtube' : 'fa-solid fa-arrow-up-right-from-square'}" aria-hidden="true"></i>
</a>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/index.html` around lines 93 - 95, The anchor that renders the source
icon (the <a> that uses s.source and contains the <i> element) lacks an
accessible label; update its markup to include an accessible name by adding an
aria-label (and optionally a title or visually-hidden text) that describes the
destination (e.g., "Open source on YouTube" when s.source includes
'youtube.com', otherwise "Open source link"); ensure the label text is generated
from s.source or context so screen readers receive a meaningful description and
keep the existing icon for visual users.

</div>
<div class="grid grid-cols-3 gap-4 px-4 py-2">
<div class="flex flex-row items-center">
<div class="pr-2"><i class="fa-solid fa-server"></i></div>
<div class="flex-1 text-center">${s.computer}</div>
<div class="flex-1 text-center">${s.computerUrl ? `<a href="${s.computerUrl}" class="underline hover:text-amber-400" target="_blank">${s.computer}</a>` : s.computer}</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Add rel="noopener noreferrer" to the computer link opened with target="_blank" to avoid window.opener vulnerabilities.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/index.html, line 100:

<comment>Add rel="noopener noreferrer" to the computer link opened with target="_blank" to avoid window.opener vulnerabilities.</comment>

<file context>
@@ -54,14 +90,14 @@
                         <div class="flex flex-row items-center">
                             <div class="pr-2"><i class="fa-solid fa-server"></i></div>
-                            <div class="flex-1 text-center">${s.computer}</div>
+                            <div class="flex-1 text-center">${s.computerUrl ? `<a href="${s.computerUrl}" class="underline hover:text-amber-400" target="_blank">${s.computer}</a>` : s.computer}</div>
                         </div>
                         <div class="flex flex-row items-center">
</file context>
Suggested change
<div class="flex-1 text-center">${s.computerUrl ? `<a href="${s.computerUrl}" class="underline hover:text-amber-400" target="_blank">${s.computer}</a>` : s.computer}</div>
<div class="flex-1 text-center">${s.computerUrl ? `<a href="${s.computerUrl}" class="underline hover:text-amber-400" target="_blank" rel="noopener noreferrer">${s.computer}</a>` : s.computer}</div>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The dynamically generated external links to HPC center pages also use target="_blank" without rel="noopener noreferrer", which can be abused by the new tab to manipulate the originating page, so the anchor should include rel attributes. [security]

Severity Level: Major ⚠️
- CRITICAL Docs homepage HPC links expose window.opener reference.
- WARN External HPC pages can navigate original documentation tab.
- WARN Security posture of external-resource links is weakened.
Suggested change
<div class="flex-1 text-center">${s.computerUrl ? `<a href="${s.computerUrl}" class="underline hover:text-amber-400" target="_blank">${s.computer}</a>` : s.computer}</div>
<div class="flex-1 text-center">${s.computerUrl ? `<a href="${s.computerUrl}" class="underline hover:text-amber-400" target="_blank" rel="noopener noreferrer">${s.computer}</a>` : s.computer}</div>
Steps of Reproduction ✅
1. Open `docs/index.html` in a browser (homepage).

2. DOMContentLoaded handler at `docs/index.html:82-107` renders the server row, producing
the template at `docs/index.html:100` with `<a href="${s.computerUrl}" ...
target="_blank">` and no `rel`.

3. Click any HPC center link (e.g., CSCS Alps, OLCF Frontier) so it opens in a new tab due
to `target="_blank"`.

4. In the DevTools console of that new HPC tab, run `window.opener.location =
'https://example.com'` and see the original docs tab navigated, confirming the
reverse‑tabnabbing condition from missing `rel="noopener noreferrer"`.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** docs/index.html
**Line:** 100:100
**Comment:**
	*Security: The dynamically generated external links to HPC center pages also use target="_blank" without rel="noopener noreferrer", which can be abused by the new tab to manipulate the originating page, so the anchor should include rel attributes.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Ensure that dynamically generated external computer links opened in a new tab also include a rel attribute for security. [custom_rule]

Severity Level: Minor ⚠️

Suggested change
<div class="flex-1 text-center">${s.computerUrl ? `<a href="${s.computerUrl}" class="underline hover:text-amber-400" target="_blank">${s.computer}</a>` : s.computer}</div>
<div class="flex-1 text-center">${s.computerUrl ? `<a href="${s.computerUrl}" class="underline hover:text-amber-400" target="_blank" rel="noopener noreferrer">${s.computer}</a>` : s.computer}</div>
Why it matters? ⭐

Same as above: adding rel="noopener noreferrer" to programmatically-generated external links prevents window.opener access and improves security. The improved code is a minimal, correct fix that addresses a real security concern and is applicable to this PR hunk.

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** docs/index.html
**Line:** 100:100
**Comment:**
	*Custom Rule: Ensure that dynamically generated external computer links opened in a new tab also include a rel attribute for security.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

</div>
<div class="flex flex-row items-center">
<div class="pr-2"><i class="fa-solid fa-microchip"></i></div>
Expand All @@ -76,12 +110,12 @@
`).join("");

document.getElementById("ft-scaling").innerHTML = scalings.map(s => `
<div class="flex md:w-2/6 mx-auto flex-col text-white rounded bg-slate-900 rounded-b-lg">
<a href="documentation/expectedPerformance.html" class="flex md:w-2/6 mx-auto flex-col text-white rounded bg-slate-900 rounded-b-lg hover:ring-2 hover:ring-amber-400 transition-shadow no-underline">
<div class="flex-1 grid bg-white pb-2">
<img class="place-self-center" src="${s.image}" alt="${s.label}">
</div>
<div class="flex-1 p-2 font-semibold text-center">${s.label}</div>
</div>
</a>
`).join("");

fetch("https://api.github.com/repos/MFlowCode/MFC/releases/latest")
Expand Down
31 changes: 31 additions & 0 deletions docs/inject-dates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env python3
"""Inject last-updated dates into docs before Doxygen runs.

Usage: python3 inject-dates.py [source_dir]
source_dir defaults to current directory.
"""
import subprocess
import sys
from pathlib import Path
from datetime import date

src_dir = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(".")
docs_dir = src_dir / "docs" / "documentation"

for md_file in sorted(docs_dir.glob("*.md")):
if "Page last updated:" in md_file.read_text():
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inject-dates.py script reads each markdown file in its entirety into memory on line 16, then modifies it by appending content. This can cause issues if the script is run multiple times on the same files, as the check "Page last updated:" only verifies presence anywhere in the file, not whether it's already been appended at the end. This could lead to duplicate date footers being appended on subsequent builds.

Consider checking if the footer has already been added at the end of the file, or tracking which files have been processed using a more robust mechanism (e.g., a separate state file).

Suggested change
if "Page last updated:" in md_file.read_text():
content = md_file.read_text()
stripped = content.rstrip()
# Check if a "Page last updated" footer already exists at the end of the file.
tail = stripped[-1024:]
if "Page last updated:" in tail and stripped.endswith("</div>"):

Copilot uses AI. Check for mistakes.
continue

result = subprocess.run(
["git", "log", "-1", "--format=%as", "--", str(md_file)],
capture_output=True, text=True,
cwd=str(src_dir),
)
page_date = result.stdout.strip() or str(date.today())
Comment on lines +19 to +24
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The subprocess.run call does not check the return code of the git command. If git fails (e.g., file not in git history, git not available, not in a git repository), the script silently falls back to today's date. Consider adding error handling or logging to make debugging easier if the git command fails unexpectedly.

Suggested change
result = subprocess.run(
["git", "log", "-1", "--format=%as", "--", str(md_file)],
capture_output=True, text=True,
cwd=str(src_dir),
)
page_date = result.stdout.strip() or str(date.today())
try:
result = subprocess.run(
["git", "log", "-1", "--format=%as", "--", str(md_file)],
capture_output=True,
text=True,
cwd=str(src_dir),
check=True,
)
git_date = result.stdout.strip()
if git_date:
page_date = git_date
else:
raise ValueError(f"Empty git log output for {md_file}")
except (subprocess.CalledProcessError, OSError, ValueError) as exc:
print(
f"Warning: could not determine last-updated date from git for {md_file}: {exc}",
file=sys.stderr,
)
page_date = str(date.today())

Copilot uses AI. Check for mistakes.

with open(md_file, "a") as f:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing encoding='utf-8' in open()

Without an explicit encoding, the file is opened using the platform default, which is not utf-8 on some Windows and POSIX locales. All the documentation .md files use UTF-8.

🐛 Proposed fix
-    with open(md_file, "a") as f:
+    with open(md_file, "a", encoding="utf-8") as f:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
with open(md_file, "a") as f:
with open(md_file, "a", encoding="utf-8") as f:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/inject-dates.py` at line 26, The open() call that appends to markdown
files uses the system default encoding; update the with open(md_file, "a") as f:
usage to explicitly specify encoding='utf-8' so all .md files are written in
UTF-8. Locate the open call where md_file is used (the with open(md_file, "a")
context) and add the encoding parameter; ensure any other similar open(...)
usages in this script follow the same pattern.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Add encoding='utf-8' to open(). Without explicit encoding, the file uses the platform default which isn't UTF-8 on all systems. This can cause encoding errors when the documentation files contain non-ASCII characters.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/inject-dates.py, line 26:

<comment>Add `encoding='utf-8'` to `open()`. Without explicit encoding, the file uses the platform default which isn't UTF-8 on all systems. This can cause encoding errors when the documentation files contain non-ASCII characters.</comment>

<file context>
@@ -0,0 +1,31 @@
+    )
+    page_date = result.stdout.strip() or str(date.today())
+
+    with open(md_file, "a") as f:
+        f.write(
+            f"\n\n<div style='text-align:center; font-size:0.75rem; "
</file context>

f.write(
f"\n\n<div style='text-align:center; font-size:0.75rem; "
f"color:#888; padding:16px 0 0;'>"
f"Page last updated: {page_date}</div>\n"
)
Comment on lines +28 to +31
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script uses f-strings spanning multiple lines (28-30) which may have readability issues. While this works, consider using parentheses to make the multi-line f-string more explicit, or breaking it into smaller parts for better maintainability.

Suggested change
f"\n\n<div style='text-align:center; font-size:0.75rem; "
f"color:#888; padding:16px 0 0;'>"
f"Page last updated: {page_date}</div>\n"
)
f"\n\n<div style='text-align:center; font-size:0.75rem; color:#888; padding:16px 0 0;'>Page last updated: {page_date}</div>\n"
)

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +31
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script does not specify encoding when reading/writing files. While Python 3 defaults to UTF-8 on most platforms, it's better to be explicit about encoding to avoid issues on Windows or other platforms. Add encoding='utf-8' to both read_text() and the open() calls.

Copilot uses AI. Check for mistakes.
Binary file added docs/res/simulations/k.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/res/simulations/l.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/res/simulations/m.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/res/simulations/n.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/res/simulations/o.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/res/simulations/p.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/res/simulations/q.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/res/simulations/r.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/res/simulations/s.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/robots.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
User-agent: *
Allow: /

Sitemap: https://mflowcode.github.io/sitemap.txt
Sitemap: https://mflowcode.github.io/sitemap.xml
Loading