Skip to content

Conversation

@stefrado
Copy link
Contributor

Summary

Remove old module mounting react method and use cleaner web component mounting method.

Issue References

  • Taiga User Story:
  • Taiga Issue:
  • Taiga Dimpact Issue:
  • Github Issue:

Checklist

  • CHANGELOG.rst updated
    • Deployment notes added
    • Breaking changes flagged
  • Documentation updated
  • Codecov report reviewed for untested lines
  • Storybook component updated/created
  • Vitest tests added/updated
  • Updated the docker-compose.yml environment variables

Comment on lines +16 to +19
this.data = getJsonFromScriptTag<{
items: ComboBoxItem[]
selected_id?: string
}>('branch-data')!

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.

Copilot Autofix

AI about 2 months ago

The best way to fix this issue is to ensure the JSON data is robustly validated and sanitized after it is retrieved from the DOM, before it is parsed and used in the application. Specifically, after parsing, all fields that can influence what is rendered (such as items, selected_id, etc.) should be validated to ensure they match expected types/values, and any string outputs should be escaped or rendered safely to avoid injection.

The code for parsing JSON should be enhanced to:

  • Validate the parsed data structure against the expected shape.
  • Optionally strip or encode any unwanted HTML or script in string values.
  • Return undefined or throw if validation fails.

We should update getJsonFromScriptTag (and/or parseJsonSafely) to perform additional schema validation. This can be achieved with a type-guard or a schema checking function, passing in a validator where we call the util. For type-safe validation, we may use a well-known external library such as zod for runtime type-checking, or we can write a custom utility that validates each field manually.

The changes are fully contained within src/open_inwoner/react/lib/getJsonScriptData.ts, adding schema or type validation and defensive error handling.

Suggested changeset 1
src/open_inwoner/react/lib/getJsonScriptData.ts
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/open_inwoner/react/lib/getJsonScriptData.ts b/src/open_inwoner/react/lib/getJsonScriptData.ts
--- a/src/open_inwoner/react/lib/getJsonScriptData.ts
+++ b/src/open_inwoner/react/lib/getJsonScriptData.ts
@@ -4,13 +4,18 @@
  * @param id The HTML id of the script element
  * @returns The parsed JSON data or undefined if not found/invalid
  */
-export function getJsonFromScriptTag<T = unknown>(id: string): T | undefined {
+export function getJsonFromScriptTag<T = unknown>(id: string, validator?: (data: unknown) => data is T): T | undefined {
   const scriptElement = document.getElementById(id)
   if (!scriptElement?.textContent) {
     return undefined
   }
 
-  return parseJsonSafely<T>(scriptElement.textContent)
+  const parsed = parseJsonSafely(scriptElement.textContent)
+  if (validator && !validator(parsed)) {
+    console.error(`[getJsonFromScriptTag] JSON validation failed`, parsed)
+    return undefined
+  }
+  return parsed as T | undefined
 }
 
 /**
EOF
@@ -4,13 +4,18 @@
* @param id The HTML id of the script element
* @returns The parsed JSON data or undefined if not found/invalid
*/
export function getJsonFromScriptTag<T = unknown>(id: string): T | undefined {
export function getJsonFromScriptTag<T = unknown>(id: string, validator?: (data: unknown) => data is T): T | undefined {
const scriptElement = document.getElementById(id)
if (!scriptElement?.textContent) {
return undefined
}

return parseJsonSafely<T>(scriptElement.textContent)
const parsed = parseJsonSafely(scriptElement.textContent)
if (validator && !validator(parsed)) {
console.error(`[getJsonFromScriptTag] JSON validation failed`, parsed)
return undefined
}
return parsed as T | undefined
}

/**
Copilot is powered by AI and may make mistakes. Always verify output.
@codecov-commenter
Copy link

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.32%. Comparing base (cd3ee5f) to head (daa30b3).
⚠️ Report is 9 commits behind head on develop.

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #1986   +/-   ##
========================================
  Coverage    92.32%   92.32%           
========================================
  Files         1206     1206           
  Lines        45299    45309   +10     
========================================
+ Hits         41822    41833   +11     
+ Misses        3477     3476    -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

</a>
{% endfor %}
<div class="card-container card-container--columns-1 plugin-card">
<action-list>
Copy link
Collaborator

@swrichards swrichards Oct 26, 2025

Choose a reason for hiding this comment

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

@stefrado can we explore whether we can do away with the entire parse-JSON-from-tag approach, and pass it directly as an attribute?

Suggested change
<action-list>
<action-list data-items="{{ feed_item_list_json }}">

Where feed_item_list_json is json.dumps'ed in the backend.

Then in the web component you could do something like:

const items = JSON.parse(this.getAttribute('data-config'));

I think this would make the code simpler and easier to follow.

Copy link
Collaborator

Choose a reason for hiding this comment

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

(Same for the KvK branch selector)

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.

4 participants