2 Commits

Author SHA1 Message Date
e48b0c90f3 Potential fix for code scanning alert no. 3: DOM text reinterpreted as HTML
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-05-18 23:37:40 +02:00
9d8322064b Potential fix for code scanning alert no. 1: URL redirection from remote source
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-05-18 23:35:18 +02:00
10 changed files with 70 additions and 168 deletions

View File

@ -1,7 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
export UV_LINK_MODE=copy;
sudo apt update sudo apt update
sudo apt full-upgrade -y sudo apt full-upgrade -y
sudo apt autoremove -y; sudo apt autoremove -y;
@ -74,7 +72,6 @@ fi
if [ -f ~/.cache/oh-my-posh-completion.bash ]; then if [ -f ~/.cache/oh-my-posh-completion.bash ]; then
source ~/.cache/oh-my-posh-completion.bash source ~/.cache/oh-my-posh-completion.bash
fi fi
export UV_LINK_MODE=copy; export UV_LINK_MODE=copy;
EOF EOF

View File

@ -6,17 +6,17 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: "devcontainers" - package-ecosystem: devcontainers
directory: "/" directory: /
schedule: schedule:
interval: "weekly" interval: weekly
day: "tuesday" day: tuesday
time: "03:00" time: 03:00
timezone: "Europe/Amsterdam" timezone: Europe/Amsterdam
- package-ecosystem: "uv" - package-ecosystem: uv
directory: "/" directory: /
schedule: schedule:
interval: "weekly" interval: weekly
day: "tuesday" day: tuesday
time: "03:00" time: 03:00
timezone: "Europe/Amsterdam" timezone: Europe/Amsterdam

View File

@ -1,51 +0,0 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# Bandit is a security linter designed to find common security issues in Python code.
# This action will run Bandit on your codebase.
# The results of the scan will be found under the Security tab of your repository.
# https://github.com/marketplace/actions/bandit-scan is ISC licensed, by abirismyname
# https://pypi.org/project/bandit/ is Apache v2.0 licensed, by PyCQA
name: Bandit
on:
push:
branches: ["master"]
pull_request:
# The branches below must be a subset of the branches above
branches: ["master"]
schedule:
- cron: "37 3 * * 3"
jobs:
bandit:
permissions:
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Bandit Scan
uses: shundor/python-bandit-scan@ab1d87dfccc5a0ffab88be3aaac6ffe35c10d6cd
with: # optional arguments
# exit with 0, even with results found
exit_zero: true # optional, default is DEFAULT
# Github token of the repository (automatically created by Github)
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information.
# File or directory to run bandit on
# path: # optional, default is .
# Report only issues of a given severity level or higher. Can be LOW, MEDIUM or HIGH. Default is UNDEFINED (everything)
# level: # optional, default is UNDEFINED
# Report only issues of a given confidence level or higher. Can be LOW, MEDIUM or HIGH. Default is UNDEFINED (everything)
# confidence: # optional, default is UNDEFINED
# comma-separated list of paths (glob patterns supported) to exclude from scan (note that these are in addition to the excluded paths provided in the config file) (default: .svn,CVS,.bzr,.hg,.git,__pycache__,.tox,.eggs,*.egg)
# excluded_paths: # optional, default is DEFAULT
# comma-separated list of test IDs to skip
# skips: # optional, default is DEFAULT
# path to a .bandit file that supplies command line arguments
# ini_path: # optional, default is DEFAULT

View File

@ -1,61 +0,0 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow checks out code, performs a Codacy security scan
# and integrates the results with the
# GitHub Advanced Security code scanning feature. For more information on
# the Codacy security scan action usage and parameters, see
# https://github.com/codacy/codacy-analysis-cli-action.
# For more information on Codacy Analysis CLI in general, see
# https://github.com/codacy/codacy-analysis-cli.
name: Codacy Security Scan
on:
push:
branches: ["master"]
pull_request:
# The branches below must be a subset of the branches above
branches: ["master"]
schedule:
- cron: "36 10 * * 3"
permissions:
contents: read
jobs:
codacy-security-scan:
permissions:
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
name: Codacy Security Scan
runs-on: ubuntu-latest
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout code
uses: actions/checkout@v4
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@d840f886c4bd4edc059706d09c6a1586111c540b
with:
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
# You can also omit the token and run the tools that support default configurations
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
verbose: true
output: results.sarif
format: sarif
# Adjust severity of non-security issues
gh-code-scanning-compat: true
# Force 0 exit code to allow SARIF file generation
# This will handover control about PR rejection to the GitHub side
max-allowed-issues: 2147483647
# Upload the SARIF file generated in the previous step
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif

View File

@ -1,15 +1,8 @@
# default_install_hook_types: default_install_hook_types:
# - pre-commit - pre-commit
# - post-checkout - post-checkout
# - post-merge - post-merge
# - post-rewrite - post-rewrite
ci:
skip: [django-check, django-check-migrations]
default_language_version:
node: 22.15.1
python: python3.13
repos: repos:
- repo: https://github.com/adamchainz/django-upgrade - repo: https://github.com/adamchainz/django-upgrade
@ -41,21 +34,28 @@ repos:
- id: mixed-line-ending - id: mixed-line-ending
args: [--fix=lf] args: [--fix=lf]
- repo: local # - repo: https://github.com/psf/black
# rev: 22.10.0
# hooks:
# - id: black
# # HTML/Django template linting
# - repo: https://github.com/rtts/djhtml
# rev: 3.0.7
# hooks:
# - id: djhtml
# entry: djhtml --tabwidth 4
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.1.0
hooks: hooks:
- id: prettier-jinja - id: prettier
name: Prettier Jinja types_or: [javascript, jsx, ts, tsx, css, scss, html, json, yaml, markdown]
language: node
additional_dependencies: additional_dependencies:
- prettier - prettier
- prettier-plugin-jinja-template - prettier-plugin-jinja-template
types_or: [html, jinja] # types_or: [javascript, jsx, ts, tsx, css, scss, json, yaml, markdown]
entry: npx prettier --plugin=prettier-plugin-jinja-template --parser=jinja-template --write # exclude: '.*\.html$'
- id: prettier-all
name: Prettier All
language: node
types_or: [javascript, jsx, ts, tsx, css, scss, json, yaml, markdown]
entry: npx prettier --write
- repo: https://github.com/DavidAnson/markdownlint-cli2 - repo: https://github.com/DavidAnson/markdownlint-cli2
rev: v0.18.1 rev: v0.18.1
@ -77,19 +77,17 @@ repos:
- id: django-check - id: django-check
name: Django Check name: Django Check
entry: uv run python dashboard_project/manage.py check entry: uv run python dashboard_project/manage.py check
language: python language: system
pass_filenames: false pass_filenames: false
types: [python] types: [python]
always_run: true always_run: true
additional_dependencies: [uv]
- id: django-check-migrations - id: django-check-migrations
name: Django Check Migrations name: Django Check Migrations
entry: uv run python dashboard_project/manage.py makemigrations --check --dry-run entry: uv run python dashboard_project/manage.py makemigrations --check --dry-run
language: python language: system
pass_filenames: false pass_filenames: false
types: [python] types: [python]
additional_dependencies: [uv]
# Security checks # Security checks
- repo: https://github.com/pycqa/bandit - repo: https://github.com/pycqa/bandit
@ -97,7 +95,7 @@ repos:
hooks: hooks:
- id: bandit - id: bandit
args: [-c, pyproject.toml, -r, dashboard_project] args: [-c, pyproject.toml, -r, dashboard_project]
# additional_dependencies: ["bandit[toml]"] additional_dependencies: ["bandit[toml]"]
# # Type checking # # Type checking
# - repo: https://github.com/pre-commit/mirrors-mypy # - repo: https://github.com/pre-commit/mirrors-mypy

View File

@ -104,10 +104,10 @@ run-redis:
# Start all development services (web, redis, celery, celery-beat) # Start all development services (web, redis, celery, celery-beat)
run-all: run-all:
foreman start make run-redis & \
make run & \
procfile: make celery & \
foreman start make celery-beat
# Test Celery task # Test Celery task
test-celery: test-celery:
@ -122,3 +122,6 @@ init-data-integration:
# Setup development environment # Setup development environment
setup-dev: venv install-dev migrate create_default_datasource setup-dev: venv install-dev migrate create_default_datasource
@echo "Development environment setup complete" @echo "Development environment setup complete"
procfile:
foreman start

View File

@ -2,6 +2,7 @@ from django.contrib import messages
from django.contrib.admin.views.decorators import staff_member_required from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.decorators import login_required, user_passes_test from django.contrib.auth.decorators import login_required, user_passes_test
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.utils.http import url_has_allowed_host_and_scheme
from .models import ExternalDataSource from .models import ExternalDataSource
from .tasks import periodic_fetch_chat_data, refresh_specific_source from .tasks import periodic_fetch_chat_data, refresh_specific_source
@ -36,7 +37,10 @@ def manual_data_refresh(request):
) )
except Exception as e: except Exception as e:
messages.error(request, f"Failed to refresh data: {e}") messages.error(request, f"Failed to refresh data: {e}")
return redirect(request.headers.get("referer", "dashboard")) # Redirect to previous page or dashboard referer = request.headers.get("referer", "")
if url_has_allowed_host_and_scheme(referer, allowed_hosts=None):
return redirect(referer)
return redirect("dashboard") # Redirect to a safe default
@staff_member_required @staff_member_required
@ -51,4 +55,7 @@ def refresh_specific_datasource(request, source_id):
except Exception as e: except Exception as e:
messages.error(request, f"Failed to refresh data source {source.name}: {e}") messages.error(request, f"Failed to refresh data source {source.name}: {e}")
return redirect(request.headers.get("referer", "/admin/data_integration/externaldatasource/")) referer = request.headers.get("referer", "")
if url_has_allowed_host_and_scheme(referer, allowed_hosts=None):
return redirect(referer)
return redirect("/admin/data_integration/externaldatasource/") # Redirect to a safe default

View File

@ -299,6 +299,15 @@
}); });
function createToast(messageText, messageTags) { function createToast(messageText, messageTags) {
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
let toastClass = ""; let toastClass = "";
let autohide = true; let autohide = true;
let delay = 5000; let delay = 5000;
@ -329,7 +338,7 @@
<button type="button" class="btn-close ${toastClass.includes("text-white") ? "btn-close-white" : ""}" data-bs-dismiss="toast" aria-label="Close"></button> <button type="button" class="btn-close ${toastClass.includes("text-white") ? "btn-close-white" : ""}" data-bs-dismiss="toast" aria-label="Close"></button>
</div> </div>
<div class="toast-body"> <div class="toast-body">
${messageText} ${escapeHtml(messageText)}
</div> </div>
</div>`; </div>`;

View File

@ -302,9 +302,9 @@ platformdirs==4.3.8 \
# via # via
# black # black
# virtualenv # virtualenv
plotly==6.1.2 \ plotly==6.1.0 \
--hash=sha256:4fdaa228926ba3e3a213f4d1713287e69dcad1a7e66cf2025bd7d7026d5014b4 \ --hash=sha256:a29d3ed523c9d7960095693af1ee52689830df0f9c6bae3e5e92c20c4f5684c3 \
--hash=sha256:f1548a8ed9158d59e03d7fed548c7db5549f3130d9ae19293c8638c202648f6d --hash=sha256:f13f497ccc2d97f06f771a30b27fab0cbd220f2975865f4ecbc75057135521de
# via livegraphsdjango # via livegraphsdjango
pluggy==1.6.0 \ pluggy==1.6.0 \
--hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 \ --hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 \

6
uv.lock generated
View File

@ -698,15 +698,15 @@ wheels = [
[[package]] [[package]]
name = "plotly" name = "plotly"
version = "6.1.2" version = "6.1.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "narwhals" }, { name = "narwhals" },
{ name = "packaging" }, { name = "packaging" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/ae/77/431447616eda6a432dc3ce541b3f808ecb8803ea3d4ab2573b67f8eb4208/plotly-6.1.2.tar.gz", hash = "sha256:4fdaa228926ba3e3a213f4d1713287e69dcad1a7e66cf2025bd7d7026d5014b4", size = 7662971, upload-time = "2025-05-27T20:21:52.56Z" } sdist = { url = "https://files.pythonhosted.org/packages/a9/e3/66eabba0b35095027e1ae5cb2e091cd168d44362242b5496baac9a460697/plotly-6.1.0.tar.gz", hash = "sha256:f13f497ccc2d97f06f771a30b27fab0cbd220f2975865f4ecbc75057135521de", size = 7545417, upload-time = "2025-05-15T16:04:39.532Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/bf/6f/759d5da0517547a5d38aabf05d04d9f8adf83391d2c7fc33f904417d3ba2/plotly-6.1.2-py3-none-any.whl", hash = "sha256:f1548a8ed9158d59e03d7fed548c7db5549f3130d9ae19293c8638c202648f6d", size = 16265530, upload-time = "2025-05-27T20:21:46.6Z" }, { url = "https://files.pythonhosted.org/packages/ee/11/83ae52318353f9da4a88cc23e7f9dbc3d449b3f0fd6158fba15eb3c3b816/plotly-6.1.0-py3-none-any.whl", hash = "sha256:a29d3ed523c9d7960095693af1ee52689830df0f9c6bae3e5e92c20c4f5684c3", size = 16118476, upload-time = "2025-05-15T16:04:30.81Z" },
] ]
[[package]] [[package]]