Skip to content
Open
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
157 changes: 157 additions & 0 deletions docs/deployment/assets/docs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/* Eureka deployment docs — diagram enhancer.
*
* Loaded as a CLASSIC script (not an ES module) on purpose: Chrome blocks
* `<script type="module">` from file:// origins (CORS, origin "null"), which
* made the mermaid diagrams show up as raw text when the docs are opened as
* local files. A classic script + the UMD mermaid build renders reliably from
* file:// and over http.
*
* For each `.diagram` panel it:
* 1. captures the raw mermaid source (before mermaid replaces it with SVG),
* 2. renders the diagram (default view),
* 3. adds a Diagram/Source toggle and a Copy-source button.
*/
(function () {
if (typeof mermaid === "undefined") {
console.error("mermaid failed to load");
return;
}

mermaid.initialize({
startOnLoad: false,
securityLevel: "loose",
theme: "base",
fontFamily: "'IBM Plex Mono', monospace",
themeVariables: {
darkMode: true,
background: "#0e131c",
fontFamily: "'IBM Plex Mono', monospace",
fontSize: "14px",
primaryColor: "#18212f",
primaryBorderColor: "#c9f24e",
primaryTextColor: "#e9eef5",
secondaryColor: "#121927",
secondaryBorderColor: "#5fd5ee",
secondaryTextColor: "#e9eef5",
tertiaryColor: "#0e131c",
tertiaryBorderColor: "#7e8da0",
tertiaryTextColor: "#b9c4d2",
lineColor: "#5fd5ee",
textColor: "#b9c4d2",
mainBkg: "#18212f",
nodeBorder: "#c9f24e",
clusterBkg: "rgba(95,213,238,0.05)",
clusterBorder: "rgba(150,180,220,0.25)",
titleColor: "#e9eef5",
edgeLabelBackground: "#0a0e14",
actorBkg: "#18212f",
actorBorder: "#b69cff",
actorTextColor: "#e9eef5",
actorLineColor: "#7e8da0",
signalColor: "#5fd5ee",
signalTextColor: "#b9c4d2",
labelBoxBkgColor: "#121927",
labelBoxBorderColor: "#5fd5ee",
labelTextColor: "#e9eef5",
loopTextColor: "#b9c4d2",
noteBkgColor: "rgba(255,180,84,0.12)",
noteBorderColor: "#ffb454",
noteTextColor: "#e9eef5",
activationBkgColor: "#18212f",
activationBorderColor: "#c9f24e",
nodeTextColor: "#e9eef5",
},
flowchart: { curve: "basis", htmlLabels: true, padding: 14 },
sequence: { actorMargin: 46, messageAlign: "center", mirrorActors: false, useMaxWidth: true },
});

function enhance(panel) {
var pre = panel.querySelector("pre.mermaid");
if (!pre) return;

var source = pre.textContent.replace(/^\s*\n/, "").replace(/\s+$/, "");

// Views: rendered graph (holds the mermaid <pre>) and a raw-source view.
var graph = document.createElement("div");
graph.className = "dgm-graph";
graph.appendChild(pre);

var srcView = document.createElement("pre");
srcView.className = "dgm-source";
srcView.hidden = true;
var code = document.createElement("code");
code.textContent = source;
srcView.appendChild(code);

var body = document.createElement("div");
body.className = "dgm-body";
body.appendChild(graph);
body.appendChild(srcView);

// Toolbar: segmented toggle + copy.
var bar = document.createElement("div");
bar.className = "dgm-bar";
bar.innerHTML =
'<div class="dgm-seg" role="tablist">' +
'<button class="dgm-tab is-active" data-view="graph" aria-selected="true">Diagram</button>' +
'<button class="dgm-tab" data-view="source" aria-selected="false">Source</button>' +
"</div>" +
'<button class="dgm-copy" type="button" aria-label="Copy Mermaid source">Copy</button>';

var cap = panel.querySelector(".cap");
if (cap) cap.appendChild(bar);
else panel.insertBefore(bar, panel.firstChild);
panel.appendChild(body);

var tabs = bar.querySelectorAll(".dgm-tab");
tabs.forEach(function (tab) {
tab.addEventListener("click", function () {
var view = tab.getAttribute("data-view");
tabs.forEach(function (t) {
var active = t === tab;
t.classList.toggle("is-active", active);
t.setAttribute("aria-selected", active ? "true" : "false");
});
graph.hidden = view !== "graph";
srcView.hidden = view !== "source";
});
});

var copy = bar.querySelector(".dgm-copy");
copy.addEventListener("click", function () {
var done = function () {
copy.textContent = "Copied";
copy.classList.add("ok");
setTimeout(function () {
copy.textContent = "Copy";
copy.classList.remove("ok");
}, 1400);
};
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(source).then(done, fallback);
} else {
fallback();
}
function fallback() {
var range = document.createRange();
range.selectNodeContents(code);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
try { document.execCommand("copy"); } catch (e) { /* ignore */ }
sel.removeAllRanges();
done();
}
Comment on lines +135 to +144

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid showing “Copied” when fallback copy fails.

done() is called unconditionally in the fallback path, so users can see success even if copy did not happen (Line 141). Gate success on actual copy result.

Proposed fix
       function fallback() {
         var range = document.createRange();
         range.selectNodeContents(code);
         var sel = window.getSelection();
-        sel.removeAllRanges();
-        sel.addRange(range);
-        try { document.execCommand("copy"); } catch (e) { /* ignore */ }
-        sel.removeAllRanges();
-        done();
+        if (!sel) return;
+        sel.removeAllRanges();
+        sel.addRange(range);
+        var copied = false;
+        try { copied = document.execCommand("copy"); } catch (e) { copied = false; }
+        sel.removeAllRanges();
+        if (copied) done();
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/deployment/assets/docs.js` around lines 135 - 144, The fallback()
function currently calls done() unconditionally even if
document.execCommand("copy") fails; change it to capture the return value of
document.execCommand("copy") (or detect thrown exceptions) and only call done()
when copy succeeded, ensuring catch blocks and failure branches do not call
done(); keep selection cleanup (sel.removeAllRanges()) in a finally-like path so
selection is cleared regardless of success but success callback is gated on the
actual copy result.

});
}

document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll(".diagram").forEach(enhance);
// Render every mermaid block (now nested inside .dgm-graph). Pass an
// explicit querySelector — some mermaid builds throw if run() is given an
// options object without `nodes`/`querySelector` instead of defaulting.
mermaid.run({ querySelector: ".dgm-graph pre.mermaid" }).catch(function (err) {
console.error("mermaid render error:", err);
});
});
})();
57 changes: 0 additions & 57 deletions docs/deployment/assets/mermaid-init.js

This file was deleted.

28 changes: 28 additions & 0 deletions docs/deployment/assets/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,34 @@ li::marker { color: var(--signal-dim); }
.diagram .cap::before { content: "◆"; color: var(--cyan); font-size: 9px; }
.mermaid { display: flex; justify-content: center; padding: 8px; }

/* Diagram toolbar — Diagram/Source toggle + copy ------------------------- */
.diagram .cap { flex-wrap: wrap; }
.dgm-bar { display: inline-flex; align-items: center; gap: 8px; margin-left: auto; }
.dgm-seg { display: inline-flex; border: 1px solid var(--line-2); border-radius: 8px; overflow: hidden; }
.dgm-tab {
font-family: var(--mono); font-size: 11px; letter-spacing: 0.04em; text-transform: none;
padding: 5px 11px; background: transparent; color: var(--muted); border: 0; cursor: pointer;
transition: background .15s, color .15s;
}
.dgm-tab + .dgm-tab { border-left: 1px solid var(--line-2); }
.dgm-tab:not(.is-active):hover { color: var(--text); background: var(--ink-3); }
.dgm-tab.is-active { background: var(--signal); color: var(--ink); font-weight: 600; }
.dgm-copy {
font-family: var(--mono); font-size: 11px; letter-spacing: 0.04em;
padding: 5px 11px; background: var(--ink-3); color: var(--text-soft);
border: 1px solid var(--line-2); border-radius: 8px; cursor: pointer;
transition: color .15s, border-color .15s;
}
.dgm-copy:hover { color: var(--text); border-color: var(--cyan); }
.dgm-copy.ok { color: var(--signal); border-color: var(--signal-dim); }
.dgm-graph { display: flex; justify-content: center; padding: 8px; }
.dgm-source {
margin: 6px 0 0; border: 0; border-left: 3px solid var(--violet);
background: var(--ink); border-radius: 0 10px 10px 0; max-height: 540px; overflow: auto;
}
.dgm-source code { color: var(--text-soft); background: none; border: 0; padding: 0; }
[hidden] { display: none !important; }

Comment on lines +169 to +196

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Migrate new toolbar styling to Tailwind utilities.

This new block introduces custom component styling (states, colors, borders, spacing) beyond animation/layout primitives. Please move these styles to Tailwind classes (or utility composition) and keep custom CSS only for parts Tailwind cannot express.

As per coding guidelines, "**/*.{css,scss}: Use TailwindCSS for all styling; custom CSS only for animations and layout primitives that Tailwind cannot express (e.g., keyframe animations, CSS custom properties)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/deployment/assets/styles.css` around lines 169 - 196, The new diagram
toolbar CSS uses bespoke styles that must be migrated to Tailwind utilities:
replace rules for .diagram .cap, .dgm-bar, .dgm-seg, .dgm-tab (including
.dgm-tab.is-active and :hover state), .dgm-copy (including .dgm-copy.ok and
:hover), .dgm-graph, .dgm-source (and its code), and the .dgm-tab + .dgm-tab
sibling border with equivalent Tailwind classes and utility composition in the
markup; keep only minimal custom CSS for things Tailwind cannot express (e.g.,
complex keyframes or non-standard CSS custom-property logic), preserve the
[hidden] { display: none !important; } rule, and remove the duplicated styling
block from styles.css so styling lives as Tailwind utility classes and small
exception CSS (if absolutely required) for .dgm-source max-height/overflow or
the left border radius.

/* Callouts ---------------------------------------------------------------- */
.note {
border-left: 3px solid var(--accent, var(--cyan));
Expand Down
3 changes: 2 additions & 1 deletion docs/deployment/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ <h4>Rotate a secret</h4>
</div>
</footer>

<script type="module" src="assets/mermaid-init.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all deployment docs pages that load Mermaid from CDN and check for SRI/crossorigin.
rg -n 'cdn\.jsdelivr\.net/npm/mermaid@' docs/deployment/*.html
rg -n 'mermaid\.min\.js".*integrity=' docs/deployment/*.html
rg -n 'mermaid\.min\.js".*crossorigin=' docs/deployment/*.html

Repository: riethmayer/eureka

Length of output: 539


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Mermaid jsDelivr inclusions =="
rg -n 'cdn\.jsdelivr\.net/npm/mermaid@' docs/deployment/*.html

echo
echo "== SRI matches (integrity=) on mermaid.min.js tags =="
rg -n 'mermaid\.min\.js".*integrity=' docs/deployment/*.html || true

echo
echo "== crossorigin matches on mermaid.min.js tags =="
rg -n 'mermaid\.min\.js".*crossorigin=' docs/deployment/*.html || true

echo
echo "== Context around mermaid@ occurrences (check integrity/crossorigin nearby) =="
rg -n -C 2 'cdn\.jsdelivr\.net/npm/mermaid@' docs/deployment/*.html

Repository: riethmayer/eureka

Length of output: 2029


Pin Mermaid CDN and add SRI

docs/deployment/index.html loads Mermaid from jsDelivr as mermaid@11 without integrity/crossorigin, which allows silent upstream changes and weaker script integrity guarantees. The same pattern exists in docs/deployment/tradeoffs.html (line 107), docs/deployment/security.html (line 161), and docs/deployment/pipeline.html (line 149). Pin to an exact Mermaid version and add integrity + crossorigin="anonymous" to the <script> tag.

<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/deployment/index.html` at line 143, The Mermaid script tag currently
uses a floating tag
"https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"; update that tag
to pin an exact release (e.g., mermaid@11.x.y) and add SRI and crossorigin
attributes by replacing the existing <script
src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
occurrences with a tag that includes integrity="sha384-..." and
crossorigin="anonymous" (use the correct integrity hash for the chosen exact
version); make the same change for the identical script occurrences in the other
docs pages.

<script src="assets/docs.js"></script>
</body>
</html>
3 changes: 2 additions & 1 deletion docs/deployment/pipeline.html
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ <h2>Where the data goes</h2>
</div>
</footer>

<script type="module" src="assets/mermaid-init.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<script src="assets/docs.js"></script>
</body>
</html>
5 changes: 3 additions & 2 deletions docs/deployment/security.html
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ <h2>What the deployer can — and can’t — do</h2>
<thead><tr><th>Role</th><th>Grants</th><th>Why it’s needed</th></tr></thead>
<tbody>
<tr><td><code>cloudbuild.builds.editor</code></td><td>Submit / run builds</td><td>Trigger the image build</td></tr>
<tr><td><code>storage.objectAdmin</code> + bucket <code>storage.admin</code></td><td>Write to the staging bucket</td><td>Upload build source</td></tr>
<tr><td><code>storage.admin</code> <span class="pill">project</span></td><td>Bucket get/list + object write</td><td><code>builds submit</code> stages source (needs project-level bucket access)</td></tr>
<tr><td><code>serviceusage.serviceUsageConsumer</code></td><td>Use project APIs</td><td>Required for <code>builds submit</code></td></tr>
<tr><td><code>artifactregistry.writer</code></td><td>Read/write images</td><td>Reference the pushed image on deploy</td></tr>
<tr><td><code>run.admin</code></td><td>Manage Cloud Run</td><td>Create revisions, set public access</td></tr>
Expand Down Expand Up @@ -158,6 +158,7 @@ <h3>Injected, not baked</h3>
</div>
</footer>

<script type="module" src="assets/mermaid-init.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<script src="assets/docs.js"></script>
</body>
</html>
3 changes: 2 additions & 1 deletion docs/deployment/tradeoffs.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ <h2>The throughline</h2>
</div>
</footer>

<script type="module" src="assets/mermaid-init.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<script src="assets/docs.js"></script>
</body>
</html>
Loading