Skip to content

Added Social Media Manager Dashboard with Lilac Theme & Wizard Wand Cursor#2

Merged
mitanuriel merged 3 commits intomainfrom
frontend
Feb 28, 2026
Merged

Added Social Media Manager Dashboard with Lilac Theme & Wizard Wand Cursor#2
mitanuriel merged 3 commits intomainfrom
frontend

Conversation

@mitanuriel
Copy link
Copy Markdown
Owner

@mitanuriel mitanuriel commented Feb 28, 2026

Beautiful Lilac Theme

  • Soft purple and lilac color palette with golden accents
  • Playfair Display serif font for elegant headers
  • Modern Inter font for clean body text
  • Glowing effects and smooth animations

Magical Wizard Wand Cursor

  • Custom wizard wand cursor with instant response
  • Animated sparkle trail effect
  • Twinkling magical follower

Dashboard Functionality

  • Single-page social media post generator
  • Mistral AI integration (Small/Medium/Large models)
  • API key storage in browser localStorage
  • Real-time post generation
  • Copy to clipboard
  • Responsive design

Enhanced Error Handling

  • User-friendly error messages
  • Debug logging for troubleshooting
  • API key validation utility

Summary by CodeRabbit

  • New Features

    • Added a polished static dashboard UI for generating social media posts with model selection, loading states, and copy-to-clipboard.
    • Persistent API key storage and keyboard shortcut (Ctrl/Cmd+Enter) for quick submission.
  • Bug Fixes / Reliability

    • Improved request handling with clearer error messages and longer timeouts for generation requests.
  • Documentation

    • Added comprehensive dashboard docs with quick start, usage, API endpoints, shortcuts, and troubleshooting.
  • Tools

    • Added a CLI utility to validate API keys.

- Created responsive single-page dashboard for social media post generation
- Integrated with existing FastAPI backend
- Features: API key storage, multiple model selection, copy to clipboard
- Modern dark theme with animations and smooth UX
- Added run_server.py for easy startup
- Includes comprehensive dashboard documentation
- Transformed UI with soft lilac/purple color palette and gold accents
- Implemented magical wizard wand cursor with instant response (no delay)
- Added Playfair Display font for elegant, high-contrast typography
- Enhanced custom cursor with sparkle trail effects
- Improved API error handling with detailed user-friendly messages
- Added debug logging for API key validation
- Created test_api_key.py utility for troubleshooting Mistral API
- Optimized cursor follower speed (45% interpolation for smooth tracking)
- Added glowing effects and animations throughout the dashboard
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 28, 2026

Warning

Rate limit exceeded

@mitanuriel has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 13 minutes and 53 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 0068f87 and cae9ee8.

📒 Files selected for processing (7)
  • DASHBOARD.md
  • run_server.py
  • src/social_media_backend.py
  • src/static/app.js
  • src/static/index.html
  • src/static/styles.css
  • test_api_key.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch frontend

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 28, 2026

Note

Unit test generation is a public access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@mitanuriel
Copy link
Copy Markdown
Owner Author

@coderabbitai help

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 28, 2026

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
    • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
    • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit configuration file (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/social_media_backend.py (1)

1-110: ⚠️ Potential issue | 🟡 Minor

Run Black on this module to unblock CI.

The pipeline reports a Black formatting failure, and this file appears to be the one requiring reformatting.

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

In `@src/social_media_backend.py` around lines 1 - 110, This module (contains
MISTRAL_CHAT_COMPLETIONS_URL, class GeneratePostRequest, and function
generate_post) fails Black formatting; run Black on the file containing those
symbols (or run black . at repo root), reformat the file, stage the changes, and
commit so CI passes; ensure no other logic is changed—only apply Black's
automatic formatting.
🧹 Nitpick comments (1)
src/static/styles.css (1)

71-74: Add reduced-motion handling for continuous animations.

Please honor user prefers-reduced-motion settings for pulse/twinkle/sparkle/shake/spin effects.

Suggested fix
+@media (prefers-reduced-motion: reduce) {
+    *, *::before, *::after {
+        animation: none !important;
+        transition: none !important;
+    }
+}

Also applies to: 89-92, 114-117, 230-265, 301-301

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

In `@src/static/styles.css` around lines 71 - 74, The wand-glow keyframes (and
other continuous animations like pulse, twinkle, sparkle, shake, spin) must
respect the user's prefers-reduced-motion setting; add a CSS media query `@media`
(prefers-reduced-motion: reduce) that zeroes or removes animation by overriding
animation/animation-duration/animation-iteration-count for elements using
wand-glow (and the pulse, twinkle, sparkle, shake, spin classes or animation
names) and/or replaces them with a non-animated static state, and ensure
keyframe definitions remain but are not applied under the media query so the
final visual state is preserved (i.e., set transform/opacity to the desired
resting values and animation: none or animation-duration: 0s for selectors that
reference these animations).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@run_server.py`:
- Around line 8-10: Change the default server bind and autoreload behavior so
startup is safer: stop hardcoding host="0.0.0.0" and reload=True; instead
default host to "127.0.0.1" (or "localhost") and set reload to False, and make
both overrideable via environment variables (e.g., BIND_HOST / BIND_RELOAD or
similar) that are read before calling uvicorn.run so the uvicorn.run(host=...,
port=8000, reload=...) call uses the env-controlled values.

In `@src/social_media_backend.py`:
- Around line 48-50: Remove the debugging print that exposes API key fragments
and length: delete or replace the lines constructing key_preview and the print
statement that references clean_api_key, key_preview, or len(clean_api_key) so
no secret-derived value is logged; if a debug marker is needed use a constant
placeholder (e.g., "<REDACTED_API_KEY>") or log only non-secret request metadata
instead; update any references to key_preview in the surrounding function (e.g.,
where clean_api_key is processed) to avoid using the removed variable.
- Line 68: Create a small helper function (e.g., safe_parse_json(response)) that
attempts response.json() and catches json.JSONDecodeError (and ValueError for
some clients), returning the parsed dict on success or None on failure; then
replace direct response.json() calls used to build error_msg (the assignment
currently using response.json().get("message", "") if response.text else "") and
the later unprotected response.json() usage with the helper, falling back to
response.text or an empty string when safe_parse_json returns None, so
HTTPException construction always uses a string and never raises on non-JSON
bodies.

In `@src/static/app.js`:
- Line 18: Current code persists API keys in localStorage by default using
STORAGE_KEY; change this to use sessionStorage by default and make localStorage
persistence explicit and opt-in: update any get/load and save logic that
currently calls localStorage.getItem(STORAGE_KEY) or
localStorage.setItem(STORAGE_KEY, ...) to instead use sessionStorage for normal
load/save, add a user-controlled "Remember API key" checkbox (or flag) that when
checked will also write the key to localStorage and read from it on startup, and
ensure that on startup you only restore from localStorage if that opt-in flag is
present; keep the STORAGE_KEY identifier but gate localStorage access behind the
new opt-in flag and leave sessionStorage as the default storage backend.

In `@src/static/index.html`:
- Line 110: The external anchor tag that opens a new tab (the <a> element
linking to "https://github.com/mitanuriel/agentSecOps_Guardian" using
target="_blank") is missing a rel attribute and is vulnerable to
reverse-tabnabbing; update that anchor to include rel="noopener noreferrer" so
external pages cannot access window.opener and to improve security.

In `@src/static/styles.css`:
- Around line 29-37: The global CSS currently hides the native cursor via the
body selector (cursor: none) which creates an accessibility blocker if the
custom JS cursor fails; remove or guard that rule and switch to applying cursor:
none only when a class (e.g., custom-cursor-enabled) is present on body, update
any button selectors that set cursor: none (the same rule affecting buttons at
the places noted) to fall back to the native cursor unless the class is present,
and in your JS (e.g., app.js) add logic to add
document.body.classList.add('custom-cursor-enabled') only after the custom
cursor DOM and event handlers are fully initialized so the native cursor remains
as a fallback until the custom cursor is ready.

In `@test_api_key.py`:
- Around line 12-15: Remove any printing of API key metadata/preview and stop
recommending passing secrets via command-line arguments: eliminate the prints
that reference api_key (the f-strings that output length and preview) and any
CLI usage guidance around supplying the key; instead read the key from an
environment variable (os.environ.get("API_KEY")) or prompt securely
(getpass.getpass) when api_key is missing, and log only non-secret status
messages (e.g., "API key provided" or "API key missing") without revealing
length or characters; update any code paths or docs around the CLI to prefer env
var or interactive prompt rather than showing the secret in shell history or
process lists.

---

Outside diff comments:
In `@src/social_media_backend.py`:
- Around line 1-110: This module (contains MISTRAL_CHAT_COMPLETIONS_URL, class
GeneratePostRequest, and function generate_post) fails Black formatting; run
Black on the file containing those symbols (or run black . at repo root),
reformat the file, stage the changes, and commit so CI passes; ensure no other
logic is changed—only apply Black's automatic formatting.

---

Nitpick comments:
In `@src/static/styles.css`:
- Around line 71-74: The wand-glow keyframes (and other continuous animations
like pulse, twinkle, sparkle, shake, spin) must respect the user's
prefers-reduced-motion setting; add a CSS media query `@media`
(prefers-reduced-motion: reduce) that zeroes or removes animation by overriding
animation/animation-duration/animation-iteration-count for elements using
wand-glow (and the pulse, twinkle, sparkle, shake, spin classes or animation
names) and/or replaces them with a non-animated static state, and ensure
keyframe definitions remain but are not applied under the media query so the
final visual state is preserved (i.e., set transform/opacity to the desired
resting values and animation: none or animation-duration: 0s for selectors that
reference these animations).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0068f87 and bcc6cbd.

📒 Files selected for processing (7)
  • DASHBOARD.md
  • run_server.py
  • src/social_media_backend.py
  • src/static/app.js
  • src/static/index.html
  • src/static/styles.css
  • test_api_key.py

Comment thread run_server.py Outdated
Comment on lines +8 to +10
host="0.0.0.0",
port=8000,
reload=True,
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

🧩 Analysis chain

🏁 Script executed:

# Find run_server.py and check its existence
find . -name "run_server.py" -type f

Repository: mitanuriel/agentSecOps_Guardian

Length of output: 90


🏁 Script executed:

# List files in the repo to understand structure
git ls-files | head -20

Repository: mitanuriel/agentSecOps_Guardian

Length of output: 385


🏁 Script executed:

# Check for Docker, deployment, or configuration files
git ls-files | grep -E "(Dockerfile|docker-compose|\.env|\.yaml|\.yml|requirements|setup\.py|pyproject\.toml)"

Repository: mitanuriel/agentSecOps_Guardian

Length of output: 174


🏁 Script executed:

# Read run_server.py to verify the exact code
cat -n run_server.py

Repository: mitanuriel/agentSecOps_Guardian

Length of output: 417


🏁 Script executed:

# Check .env.example to see what env vars are already documented
cat -n .env.example

Repository: mitanuriel/agentSecOps_Guardian

Length of output: 474


🏁 Script executed:

# Check the Dockerfile if it exists
find . -name "Dockerfile*" -type f -exec cat -n {} \;

Repository: mitanuriel/agentSecOps_Guardian

Length of output: 57


🏁 Script executed:

# Check CI workflow to see how the app is intended to be started
cat -n .github/workflows/ci.yml

Repository: mitanuriel/agentSecOps_Guardian

Length of output: 1915


🏁 Script executed:

# Check README for deployment/startup instructions
cat README.md

Repository: mitanuriel/agentSecOps_Guardian

Length of output: 3889


Restrict default bind/reload settings for safer startup.

Line 8 binds to all interfaces and Line 10 enables reload by default. Even for development, binding to 0.0.0.0 exposes the server to all network interfaces, which is risky on shared networks. Default to localhost and make external bind and reload opt-in via environment variables.

Suggested fix
+import os
 import uvicorn
 
 if __name__ == "__main__":
     uvicorn.run(
         "src.social_media_backend:app",
-        host="0.0.0.0",
+        host=os.getenv("HOST", "127.0.0.1"),
         port=8000,
-        reload=True,
+        reload=os.getenv("UVICORN_RELOAD", "false").lower() == "true",
         log_level="info"
     )
📝 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
host="0.0.0.0",
port=8000,
reload=True,
import os
import uvicorn
if __name__ == "__main__":
uvicorn.run(
"src.social_media_backend:app",
host=os.getenv("HOST", "127.0.0.1"),
port=8000,
reload=os.getenv("UVICORN_RELOAD", "false").lower() == "true",
log_level="info"
)
🧰 Tools
🪛 Ruff (0.15.2)

[error] 8-8: Possible binding to all interfaces

(S104)

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

In `@run_server.py` around lines 8 - 10, Change the default server bind and
autoreload behavior so startup is safer: stop hardcoding host="0.0.0.0" and
reload=True; instead default host to "127.0.0.1" (or "localhost") and set reload
to False, and make both overrideable via environment variables (e.g., BIND_HOST
/ BIND_RELOAD or similar) that are read before calling uvicorn.run so the
uvicorn.run(host=..., port=8000, reload=...) call uses the env-controlled
values.

Comment on lines +48 to +50
# Log key format for debugging (first/last 4 chars only)
key_preview = f"{clean_api_key[:4]}...{clean_api_key[-4:]}" if len(clean_api_key) > 8 else "***"
print(f"DEBUG: Using API key: {key_preview}, length: {len(clean_api_key)}")
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

Remove API-key fingerprint logging from request path.

Lines 48-50 log key preview and length. Secret-derived values should not be emitted to logs.

Suggested fix
-        # Log key format for debugging (first/last 4 chars only)
-        key_preview = f"{clean_api_key[:4]}...{clean_api_key[-4:]}" if len(clean_api_key) > 8 else "***"
-        print(f"DEBUG: Using API key: {key_preview}, length: {len(clean_api_key)}")
📝 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
# Log key format for debugging (first/last 4 chars only)
key_preview = f"{clean_api_key[:4]}...{clean_api_key[-4:]}" if len(clean_api_key) > 8 else "***"
print(f"DEBUG: Using API key: {key_preview}, length: {len(clean_api_key)}")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/social_media_backend.py` around lines 48 - 50, Remove the debugging print
that exposes API key fragments and length: delete or replace the lines
constructing key_preview and the print statement that references clean_api_key,
key_preview, or len(clean_api_key) so no secret-derived value is logged; if a
debug marker is needed use a constant placeholder (e.g., "<REDACTED_API_KEY>")
or log only non-secret request metadata instead; update any references to
key_preview in the surrounding function (e.g., where clean_api_key is processed)
to avoid using the removed variable.

# Handle API errors with helpful messages
if response.status_code == 401:
from fastapi import HTTPException
error_msg = response.json().get("message", "") if response.text else ""
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

🧩 Analysis chain

🏁 Script executed:

cat -n src/social_media_backend.py | sed -n '50,100p'

Repository: mitanuriel/agentSecOps_Guardian

Length of output: 2420


Safely parse non-JSON error responses before building HTTP errors.

Lines 68 and 82 call response.json() directly without handling potential json.JSONDecodeError. If the upstream API returns an error response with a non-JSON body, these calls will raise an unhandled exception, bypassing your intended HTTPException handling. Line 68's check of response.text only verifies content exists, not that it's valid JSON. Line 82 has no protection whatsoever.

Create a helper function to safely parse responses:

Suggested fix
+def _safe_json(response: requests.Response) -> dict:
+    try:
+        return response.json()
+    except ValueError:
+        return {}
+
         if response.status_code == 401:
             from fastapi import HTTPException
-            error_msg = response.json().get("message", "") if response.text else ""
+            body = _safe_json(response)
+            error_msg = body.get("message", "") if response.text else ""
             print(f"DEBUG: 401 error details - {error_msg}")
         elif response.status_code >= 400:
             from fastapi import HTTPException
-            error_detail = response.json().get("error", {}).get("message", "Unknown error")
+            body = _safe_json(response)
+            error_detail = body.get("error", {}).get("message", "Unknown error")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/social_media_backend.py` at line 68, Create a small helper function
(e.g., safe_parse_json(response)) that attempts response.json() and catches
json.JSONDecodeError (and ValueError for some clients), returning the parsed
dict on success or None on failure; then replace direct response.json() calls
used to build error_msg (the assignment currently using
response.json().get("message", "") if response.text else "") and the later
unprotected response.json() usage with the helper, falling back to response.text
or an empty string when safe_parse_json returns None, so HTTPException
construction always uses a string and never raises on non-JSON bodies.

Comment thread src/static/app.js
const API_BASE_URL = window.location.origin;

// Local Storage for API Key
const STORAGE_KEY = 'mistral_api_key';
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

🧩 Analysis chain

🏁 Script executed:

cat -n src/static/app.js

Repository: mitanuriel/agentSecOps_Guardian

Length of output: 7903


Remove default localStorage persistence for API keys; use sessionStorage by default.

The code stores API keys to localStorage (lines 95-97) and reloads them on startup (lines 74-79) without any user opt-in. This exposes long-lived secrets to XSS attacks on the same origin. Use sessionStorage by default and make localStorage persistence an explicit, user-controlled opt-in via a checkbox.

Suggested fix
 const STORAGE_KEY = 'mistral_api_key';
+const REMEMBER_KEY = false; // wire to an explicit "Remember key" checkbox
 
 // Load saved API key on page load
 window.addEventListener('DOMContentLoaded', () => {
-    const savedKey = localStorage.getItem(STORAGE_KEY);
+    const savedKey = sessionStorage.getItem(STORAGE_KEY) || localStorage.getItem(STORAGE_KEY);
     if (savedKey) {
         document.getElementById('apiKey').value = savedKey;
     }
 });
@@
-    // Save API key to local storage
-    localStorage.setItem(STORAGE_KEY, apiKey);
+    if (REMEMBER_KEY) {
+        localStorage.setItem(STORAGE_KEY, apiKey);
+    } else {
+        sessionStorage.setItem(STORAGE_KEY, apiKey);
+        localStorage.removeItem(STORAGE_KEY);
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/static/app.js` at line 18, Current code persists API keys in localStorage
by default using STORAGE_KEY; change this to use sessionStorage by default and
make localStorage persistence explicit and opt-in: update any get/load and save
logic that currently calls localStorage.getItem(STORAGE_KEY) or
localStorage.setItem(STORAGE_KEY, ...) to instead use sessionStorage for normal
load/save, add a user-controlled "Remember API key" checkbox (or flag) that when
checked will also write the key to localStorage and read from it on startup, and
ensure that on startup you only restore from localStorage if that opt-in flag is
present; keep the STORAGE_KEY identifier but gate localStorage access behind the
new opt-in flag and leave sessionStorage as the default storage backend.

Comment thread src/static/index.html
</main>

<footer>
<p>Built for Mistral AI Hackathon 2026 | <a href="https://github.com/mitanuriel/agentSecOps_Guardian" target="_blank">GitHub</a></p>
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

Add rel="noopener noreferrer" to external links opened with _blank.

Line 110 uses target="_blank" without rel, which allows reverse-tabnabbing.

Suggested fix
-<p>Built for Mistral AI Hackathon 2026 | <a href="https://github.com/mitanuriel/agentSecOps_Guardian" target="_blank">GitHub</a></p>
+<p>Built for Mistral AI Hackathon 2026 | <a href="https://github.com/mitanuriel/agentSecOps_Guardian" target="_blank" rel="noopener noreferrer">GitHub</a></p>
📝 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
<p>Built for Mistral AI Hackathon 2026 | <a href="https://github.com/mitanuriel/agentSecOps_Guardian" target="_blank">GitHub</a></p>
<p>Built for Mistral AI Hackathon 2026 | <a href="https://github.com/mitanuriel/agentSecOps_Guardian" target="_blank" rel="noopener noreferrer">GitHub</a></p>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/static/index.html` at line 110, The external anchor tag that opens a new
tab (the <a> element linking to
"https://github.com/mitanuriel/agentSecOps_Guardian" using target="_blank") is
missing a rel attribute and is vulnerable to reverse-tabnabbing; update that
anchor to include rel="noopener noreferrer" so external pages cannot access
window.opener and to improve security.

Comment thread src/static/styles.css
Comment on lines +29 to +37
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background: linear-gradient(135deg, #1e1b2e 0%, #2d1b3d 50%, #1e1b2e 100%);
color: var(--text-primary);
min-height: 100vh;
padding: 20px;
line-height: 1.6;
cursor: none;
}
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

Keep native cursor as fallback to avoid an accessibility blocker.

Global cursor: none (Line 36) plus button-level cursor: none (Lines 187 and 222) hides pointer affordance if custom JS cursor fails/loads late. Hide cursor only after JS explicitly enables custom-cursor mode.

Suggested fix
 body {
@@
-    cursor: none;
+    cursor: auto;
 }
+
+body.custom-cursor-enabled {
+    cursor: none;
+}
@@
 .btn-primary, .btn-secondary {
@@
-    cursor: none;
+    cursor: pointer;
@@
 }
@@
-.btn-primary:disabled { opacity: 0.6; cursor: none; transform: none; }
+.btn-primary:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }
// additionally in app.js (after custom cursor elements are added)
document.body.classList.add('custom-cursor-enabled');

Also applies to: 180-188, 222-222

🧰 Tools
🪛 Stylelint (17.3.0)

[error] 30-30: Unexpected quotes around "Inter" (font-family-name-quotes)

(font-family-name-quotes)

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

In `@src/static/styles.css` around lines 29 - 37, The global CSS currently hides
the native cursor via the body selector (cursor: none) which creates an
accessibility blocker if the custom JS cursor fails; remove or guard that rule
and switch to applying cursor: none only when a class (e.g.,
custom-cursor-enabled) is present on body, update any button selectors that set
cursor: none (the same rule affecting buttons at the places noted) to fall back
to the native cursor unless the class is present, and in your JS (e.g., app.js)
add logic to add document.body.classList.add('custom-cursor-enabled') only after
the custom cursor DOM and event handlers are fully initialized so the native
cursor remains as a fallback until the custom cursor is ready.

Comment thread test_api_key.py Outdated
Comment on lines +12 to +15
print(f"Testing API key...")
print(f" Length: {len(api_key)} characters")
print(f" Preview: {api_key[:4]}...{api_key[-4:]}" if len(api_key) > 8 else " Key too short!")
print()
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

Avoid leaking key material via logs and CLI arguments.

Lines 12-15 print key metadata/preview, and Lines 56-60 encourage passing secrets via CLI (visible in shell history/process list). Prefer env var or interactive prompt and remove preview logging.

Suggested fix
-    print(f"Testing API key...")
-    print(f"  Length: {len(api_key)} characters")
-    print(f"  Preview: {api_key[:4]}...{api_key[-4:]}" if len(api_key) > 8 else "  Key too short!")
+    print("Testing API key...")
     print()
@@
-        print("Usage: python test_api_key.py YOUR_API_KEY")
+        print("Usage: MISTRAL_API_KEY='your-key-here' python test_api_key.py")

Also applies to: 56-60

🧰 Tools
🪛 Ruff (0.15.2)

[error] 12-12: f-string without any placeholders

Remove extraneous f prefix

(F541)

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

In `@test_api_key.py` around lines 12 - 15, Remove any printing of API key
metadata/preview and stop recommending passing secrets via command-line
arguments: eliminate the prints that reference api_key (the f-strings that
output length and preview) and any CLI usage guidance around supplying the key;
instead read the key from an environment variable (os.environ.get("API_KEY")) or
prompt securely (getpass.getpass) when api_key is missing, and log only
non-secret status messages (e.g., "API key provided" or "API key missing")
without revealing length or characters; update any code paths or docs around the
CLI to prefer env var or interactive prompt rather than showing the secret in
shell history or process lists.

@mitanuriel
Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 28, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (7)
run_server.py (1)

8-10: ⚠️ Potential issue | 🟠 Major

Harden default bind/reload behavior for safer local startup.

Line 8 binds to all interfaces and Line 10 enables reload unconditionally. Keep localhost and reload-off as defaults, and make both opt-in via env vars.

Suggested fix
+import os
 import uvicorn
 
 if __name__ == "__main__":
+    host = os.getenv("BIND_HOST", "127.0.0.1")
+    reload_enabled = os.getenv("BIND_RELOAD", "false").lower() == "true"
     uvicorn.run(
         "src.social_media_backend:app",
-        host="0.0.0.0",
+        host=host,
         port=8000,
-        reload=True,
+        reload=reload_enabled,
         log_level="info"
     )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@run_server.py` around lines 8 - 10, Change the hardcoded uvicorn startup args
to safer defaults and make binding/reload opt-in: set host default to
"127.0.0.1" instead of "0.0.0.0" and keep reload disabled by default; read an
environment variable (e.g., START_PUBLIC or BIND_ALL) to allow binding to
0.0.0.0 and another env var (e.g., ENABLE_RELOAD or DEV_RELOAD) to enable
reload. Update the uvicorn.run(...) call (the block that currently passes
host="0.0.0.0", port=8000, reload=True) to use os.getenv checks to choose host
and reload values, and document or name the env vars clearly so startup remains
localhost/no-reload unless explicitly opted-in.
src/static/index.html (1)

110-110: ⚠️ Potential issue | 🟠 Major

Add rel="noopener noreferrer" on external _blank link.

Line 110 opens a new tab without rel, which leaves reverse-tabnabbing exposure.

Suggested fix
-<p>Built for Mistral AI Hackathon 2026 | <a href="https://github.com/mitanuriel/agentSecOps_Guardian" target="_blank">GitHub</a></p>
+<p>Built for Mistral AI Hackathon 2026 | <a href="https://github.com/mitanuriel/agentSecOps_Guardian" target="_blank" rel="noopener noreferrer">GitHub</a></p>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/static/index.html` at line 110, The external anchor link with href
"https://github.com/mitanuriel/agentSecOps_Guardian" that opens in a new tab
(target="_blank") should include rel="noopener noreferrer" to prevent
reverse-tabnabbing; update the <a> element for that GitHub link in
src/static/index.html to add rel="noopener noreferrer" while preserving the
existing target and link text.
src/social_media_backend.py (2)

68-68: ⚠️ Potential issue | 🟠 Major

Safely parse upstream error bodies before reading JSON fields.

Line 68 and Line 82 call response.json() directly. Non-JSON error responses will raise and bypass intended HTTPException handling.

Suggested fix
+def _safe_json(response: requests.Response) -> dict:
+    try:
+        return response.json()
+    except ValueError:
+        return {}
+
@@
         if response.status_code == 401:
             from fastapi import HTTPException
-            error_msg = response.json().get("message", "") if response.text else ""
+            error_msg = _safe_json(response).get("message", "") if response.text else ""
             print(f"DEBUG: 401 error details - {error_msg}")
@@
         elif response.status_code >= 400:
             from fastapi import HTTPException
-            error_detail = response.json().get("error", {}).get("message", "Unknown error")
+            error_detail = _safe_json(response).get("error", {}).get("message", "Unknown error")

Also applies to: 82-82

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

In `@src/social_media_backend.py` at line 68, The code calls response.json()
directly when building error_msg (e.g., the variable error_msg and the
error-handling blocks around those response usages), which will raise on
non-JSON error bodies; instead, guard JSON parsing by checking Content-Type for
application/json or wrapping response.json() in a try/except (catch
ValueError/JSONDecodeError) and fall back to response.text (or an empty string)
before raising the HTTPException — update both places that call response.json()
so they safely parse or fallback and include the safe message in the
HTTPException.

48-50: ⚠️ Potential issue | 🟠 Major

Remove API-key fingerprint logging from request flow.

Line 50 logs secret-derived key preview/length. This should not be emitted in server logs.

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

In `@src/social_media_backend.py` around lines 48 - 50, Remove the secret-derived
API key preview and length logging: delete the key_preview computation and the
print statement that references clean_api_key (the lines computing key_preview
and the print(f"DEBUG: Using API key...")). If you still need a trace, replace
with a non-sensitive log such as a single message like "DEBUG: API key provided"
or no-op, but do not include clean_api_key, key_preview, or its length anywhere
in logs; update any callers in this module that rely on key_preview accordingly.
src/static/styles.css (1)

29-37: ⚠️ Potential issue | 🟠 Major

Keep native cursor fallback unless custom cursor is explicitly enabled.

Global and button-level cursor: none creates an accessibility blocker when custom cursor init fails/loads late. Gate cursor-hiding behind a body class enabled by JS after cursor setup.

Suggested fix
 body {
@@
-    cursor: none;
+    cursor: auto;
 }
+
+body.custom-cursor-enabled {
+    cursor: none;
+}
@@
 .btn-primary, .btn-secondary {
@@
-    cursor: none;
+    cursor: pointer;
@@
 }
@@
-.btn-primary:disabled { opacity: 0.6; cursor: none; transform: none; }
+.btn-primary:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }

Also add in src/static/app.js right after cursor/follower setup:

document.body.classList.add('custom-cursor-enabled');

Also applies to: 180-188, 222-222

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

In `@src/static/styles.css` around lines 29 - 37, The global CSS rule hiding the
cursor on the body (`body { cursor: none; }`) is unsafe; remove that global
`cursor: none` and instead add a scoped rule that only hides the cursor when a
JS-enabled flag class is present (e.g. create a `.custom-cursor-enabled`
selector that applies `cursor: none` to `body` and any button selectors that
previously relied on the global rule). Then, in your cursor initialization code
in app.js, after the cursor/follower setup completes, add a call to add the flag
class to the document body (use
`document.body.classList.add('custom-cursor-enabled')`) so the custom cursor is
only hidden if JS successfully initialized it.
test_api_key.py (1)

12-15: ⚠️ Potential issue | 🟠 Major

Stop leaking API-key metadata and avoid CLI-secret input.

Line 13–14 exposes key-derived metadata, and Line 70 reads secrets from argv (visible in shell history/process listings). Prefer env var or secure prompt only.

Suggested fix
+import os
+import getpass
 import sys
 import requests
@@
 def test_mistral_key(api_key: str) -> None:
@@
-    print(f"Testing API key...")
-    print(f"  Length: {len(api_key)} characters")
-    print(f"  Preview: {api_key[:4]}...{api_key[-4:]}" if len(api_key) > 8 else "  Key too short!")
+    print("Testing API key...")
     print()
@@
 if __name__ == "__main__":
-    if len(sys.argv) < 2:
-        print("Usage: python test_api_key.py YOUR_API_KEY")
-        print("\nOr set MISTRAL_API_KEY environment variable:")
-        print("  export MISTRAL_API_KEY='your-key-here'")
-        print("  python test_api_key.py")
-        
-        import os
-        api_key = os.getenv("MISTRAL_API_KEY")
-        if api_key:
-            print("\nFound MISTRAL_API_KEY in environment, testing...")
-            test_mistral_key(api_key)
-        else:
-            sys.exit(1)
-    else:
-        test_mistral_key(sys.argv[1])
+    api_key = os.getenv("MISTRAL_API_KEY") or getpass.getpass("Enter Mistral API key: ")
+    if not api_key:
+        sys.exit(1)
+    test_mistral_key(api_key)

Also applies to: 56-60, 70-70

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

In `@test_api_key.py` around lines 12 - 15, Remove any CLI printing of API key
metadata (the prints that reference api_key, its length, and preview) so the
test does not leak secrets; instead validate without logging key content.
Replace reading secrets from argv (where sys.argv or argparse parses the secret
at the noted spot) with a secure source: read from an environment variable
(os.environ["API_KEY"] or similar) or prompt securely via getpass.getpass() and
fail fast if missing. Update any other occurrences that print or expose api_key
(the prints at the other mentioned ranges) to ensure no key, length, or preview
is emitted.
src/static/app.js (1)

74-79: ⚠️ Potential issue | 🟠 Major

Do not persist API keys in localStorage by default.

Line 76 and Line 96 store/retrieve long-lived secrets from localStorage without explicit opt-in. Use sessionStorage by default and gate localStorage behind a user “Remember key” choice.

Also applies to: 95-97

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

In `@src/static/app.js` around lines 74 - 79, The code currently reads and writes
long-lived API keys directly to localStorage; change the default to use
sessionStorage for getItem/setItem in the DOMContentLoaded loader and in the
save logic, and only write to localStorage when the user explicitly opts-in via
a "Remember key" checkbox. Concretely: in the
window.addEventListener('DOMContentLoaded', ...) loader and the counterpart save
handler that references STORAGE_KEY and document.getElementById('apiKey'),
switch to sessionStorage.getItem/sessionStorage.setItem by default and add a
conditional that writes to localStorage only if a
document.getElementById('rememberKey') checkbox is checked (otherwise clear
localStorage entry if present). Ensure both load and save paths consistently
honor the rememberKey option.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/social_media_backend.py`:
- Around line 41-110: The file fails CI because it is not formatted to Black's
expectations; run Black (e.g., black src/social_media_backend.py or black src
tests) to reformat the file, verify generate_post and its surrounding code are
reformatted (PEP8/Black style), stage and commit the changes, and push so the
pipeline's `black --check src tests` passes.

In `@src/static/index.html`:
- Line 36: The privacy hint text is inaccurate: the page currently claims the
API key is "never sent to our servers" but the client does POST the api_key to
the /generate-post endpoint; update the <small class="hint"> text to accurately
reflect handling (e.g., state that the key is sent to this server endpoint for
processing or removed/obfuscated client-side) so users aren’t misled, and ensure
the copy references the api_key submission to /generate-post or clarifies key
storage only occurs locally if that is true; locate the string in
src/static/index.html (the small.hint element) and replace it with the corrected
wording.

---

Duplicate comments:
In `@run_server.py`:
- Around line 8-10: Change the hardcoded uvicorn startup args to safer defaults
and make binding/reload opt-in: set host default to "127.0.0.1" instead of
"0.0.0.0" and keep reload disabled by default; read an environment variable
(e.g., START_PUBLIC or BIND_ALL) to allow binding to 0.0.0.0 and another env var
(e.g., ENABLE_RELOAD or DEV_RELOAD) to enable reload. Update the
uvicorn.run(...) call (the block that currently passes host="0.0.0.0",
port=8000, reload=True) to use os.getenv checks to choose host and reload
values, and document or name the env vars clearly so startup remains
localhost/no-reload unless explicitly opted-in.

In `@src/social_media_backend.py`:
- Line 68: The code calls response.json() directly when building error_msg
(e.g., the variable error_msg and the error-handling blocks around those
response usages), which will raise on non-JSON error bodies; instead, guard JSON
parsing by checking Content-Type for application/json or wrapping
response.json() in a try/except (catch ValueError/JSONDecodeError) and fall back
to response.text (or an empty string) before raising the HTTPException — update
both places that call response.json() so they safely parse or fallback and
include the safe message in the HTTPException.
- Around line 48-50: Remove the secret-derived API key preview and length
logging: delete the key_preview computation and the print statement that
references clean_api_key (the lines computing key_preview and the print(f"DEBUG:
Using API key...")). If you still need a trace, replace with a non-sensitive log
such as a single message like "DEBUG: API key provided" or no-op, but do not
include clean_api_key, key_preview, or its length anywhere in logs; update any
callers in this module that rely on key_preview accordingly.

In `@src/static/app.js`:
- Around line 74-79: The code currently reads and writes long-lived API keys
directly to localStorage; change the default to use sessionStorage for
getItem/setItem in the DOMContentLoaded loader and in the save logic, and only
write to localStorage when the user explicitly opts-in via a "Remember key"
checkbox. Concretely: in the window.addEventListener('DOMContentLoaded', ...)
loader and the counterpart save handler that references STORAGE_KEY and
document.getElementById('apiKey'), switch to
sessionStorage.getItem/sessionStorage.setItem by default and add a conditional
that writes to localStorage only if a document.getElementById('rememberKey')
checkbox is checked (otherwise clear localStorage entry if present). Ensure both
load and save paths consistently honor the rememberKey option.

In `@src/static/index.html`:
- Line 110: The external anchor link with href
"https://github.com/mitanuriel/agentSecOps_Guardian" that opens in a new tab
(target="_blank") should include rel="noopener noreferrer" to prevent
reverse-tabnabbing; update the <a> element for that GitHub link in
src/static/index.html to add rel="noopener noreferrer" while preserving the
existing target and link text.

In `@src/static/styles.css`:
- Around line 29-37: The global CSS rule hiding the cursor on the body (`body {
cursor: none; }`) is unsafe; remove that global `cursor: none` and instead add a
scoped rule that only hides the cursor when a JS-enabled flag class is present
(e.g. create a `.custom-cursor-enabled` selector that applies `cursor: none` to
`body` and any button selectors that previously relied on the global rule).
Then, in your cursor initialization code in app.js, after the cursor/follower
setup completes, add a call to add the flag class to the document body (use
`document.body.classList.add('custom-cursor-enabled')`) so the custom cursor is
only hidden if JS successfully initialized it.

In `@test_api_key.py`:
- Around line 12-15: Remove any CLI printing of API key metadata (the prints
that reference api_key, its length, and preview) so the test does not leak
secrets; instead validate without logging key content. Replace reading secrets
from argv (where sys.argv or argparse parses the secret at the noted spot) with
a secure source: read from an environment variable (os.environ["API_KEY"] or
similar) or prompt securely via getpass.getpass() and fail fast if missing.
Update any other occurrences that print or expose api_key (the prints at the
other mentioned ranges) to ensure no key, length, or preview is emitted.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0068f87 and bcc6cbd.

📒 Files selected for processing (7)
  • DASHBOARD.md
  • run_server.py
  • src/social_media_backend.py
  • src/static/app.js
  • src/static/index.html
  • src/static/styles.css
  • test_api_key.py

Comment on lines 41 to +110
@app.post("/generate-post")
def generate_post(payload: GeneratePostRequest) -> dict:
"""Generate a social media post from a user prompt using Mistral."""
response = requests.post(
MISTRAL_CHAT_COMPLETIONS_URL,
headers={
"Authorization": f"Bearer {payload.api_key}",
"Content-Type": "application/json",
},
json={
try:
# Clean the API key (remove any whitespace)
clean_api_key = payload.api_key.strip()

# Log key format for debugging (first/last 4 chars only)
key_preview = f"{clean_api_key[:4]}...{clean_api_key[-4:]}" if len(clean_api_key) > 8 else "***"
print(f"DEBUG: Using API key: {key_preview}, length: {len(clean_api_key)}")

response = requests.post(
MISTRAL_CHAT_COMPLETIONS_URL,
headers={
"Authorization": f"Bearer {clean_api_key}",
"Content-Type": "application/json",
},
json={
"model": payload.model,
"messages": [{"role": "user", "content": payload.prompt}],
},
timeout=60,
)

# Handle API errors with helpful messages
if response.status_code == 401:
from fastapi import HTTPException
error_msg = response.json().get("message", "") if response.text else ""
print(f"DEBUG: 401 error details - {error_msg}")
raise HTTPException(
status_code=401,
detail=f"Invalid API key. Check: 1) Key is correctly copied from Mistral console 2) No extra spaces 3) Key is activated. API response: {error_msg}"
)
elif response.status_code == 429:
from fastapi import HTTPException
raise HTTPException(
status_code=429,
detail="Rate limit exceeded. Please wait a moment and try again."
)
elif response.status_code >= 400:
from fastapi import HTTPException
error_detail = response.json().get("error", {}).get("message", "Unknown error")
raise HTTPException(
status_code=response.status_code,
detail=f"Mistral API error: {error_detail}"
)

response.raise_for_status()

completion = response.json()
post_text = completion["choices"][0]["message"]["content"]

return {
"post": post_text,
"model": payload.model,
"messages": [{"role": "user", "content": payload.prompt}],
},
timeout=60,
)
response.raise_for_status()

completion = response.json()
post_text = completion["choices"][0]["message"]["content"]

return {
"post": post_text,
"model": payload.model,
"provider": "mistral",
}
"provider": "mistral",
}

except requests.exceptions.Timeout:
from fastapi import HTTPException
raise HTTPException(
status_code=504,
detail="Request timeout. The API took too long to respond. Please try again."
)
except requests.exceptions.RequestException as e:
from fastapi import HTTPException
raise HTTPException(
status_code=500,
detail=f"Network error: {str(e)}"
)
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

CI is currently blocked by formatting in this file.

Pipeline reports black --check src tests failing with this file needing reformatting. Please run Black and commit the formatted output to unblock merge.

🧰 Tools
🪛 Ruff (0.15.2)

[warning] 93-97: Consider moving this statement to an else block

(TRY300)


[warning] 101-104: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


[warning] 107-110: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


[warning] 109-109: Use explicit conversion flag

Replace with conversion flag

(RUF010)

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

In `@src/social_media_backend.py` around lines 41 - 110, The file fails CI because
it is not formatted to Black's expectations; run Black (e.g., black
src/social_media_backend.py or black src tests) to reformat the file, verify
generate_post and its surrounding code are reformatted (PEP8/Black style), stage
and commit the changes, and push so the pipeline's `black --check src tests`
passes.

Comment thread src/static/index.html
placeholder="Enter your Mistral API key"
required
>
<small class="hint">Your key is stored locally and never sent to our servers</small>
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

Fix inaccurate privacy wording for API key handling.

Line 36 says the key is “never sent to our servers,” but the client sends api_key to /generate-post. This is misleading for users and should be corrected.

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

In `@src/static/index.html` at line 36, The privacy hint text is inaccurate: the
page currently claims the API key is "never sent to our servers" but the client
does POST the api_key to the /generate-post endpoint; update the <small
class="hint"> text to accurately reflect handling (e.g., state that the key is
sent to this server endpoint for processing or removed/obfuscated client-side)
so users aren’t misled, and ensure the copy references the api_key submission to
/generate-post or clarifies key storage only occurs locally if that is true;
locate the string in src/static/index.html (the small.hint element) and replace
it with the corrected wording.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 28, 2026

✅ Created PR with unit tests: #3

- Change run_server.py to bind to 127.0.0.1 by default (not 0.0.0.0)
- Disable auto-reload by default in production
- Add environment variables (BIND_HOST, BIND_PORT, BIND_RELOAD) for configuration
- Remove API key exposure from test_api_key.py (no length/preview logging)
- Replace command-line argument with secure getpass prompt
- Read API key from MISTRAL_API_KEY environment variable or secure prompt
- Prevent API keys from appearing in shell history or terminal output
@mitanuriel mitanuriel merged commit f429166 into main Feb 28, 2026
1 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant