--- name: fix-csp-compliance description: | Fix Content Security Policy (CSP) compliance issues that UI5 linter reports but cannot auto-fix. Use this skill when linter outputs: - `csp-unsafe-inline-script` with message "Use of unsafe inline script" Trigger on: inline JavaScript in HTML files, script tags without src attribute, onclick/onload handlers in HTML. Also use when user mentions 'security headers', 'inline script warning', 'CSP policy', 'unsafe-inline', or 'Content-Security-Policy'. Provides guidance on moving inline scripts to external files for CSP compliance. --- # Fix CSP Compliance - Unsafe Inline Scripts ## Key Rules 1. **NEVER delete inline script content.** Always extract it to an external `.js` file and replace the inline `` with ``. Even trivial config objects, debug flags, or seemingly unused code must be externalized — removal is a functional regression. 2. File naming: use a descriptive name matching the content's purpose (e.g., `appConfig.js` for configuration, `init.js` for initialization). This skill fixes Content Security Policy (CSP) compliance issues that the UI5 linter detects but cannot auto-fix because they require restructuring code into external files. ## Linter Rule Handled | Rule ID | Message Pattern | Severity | This Skill's Action | |---------|-----------------|----------|---------------------| | `csp-unsafe-inline-script` | Use of unsafe inline script | Warning | Move to external JS file | ## When to Use Apply this skill when you see linter output like: ``` index.html:15:5 warning Use of unsafe inline script csp-unsafe-inline-script test.html:20:5 warning Use of unsafe inline script csp-unsafe-inline-script ``` ## Background: Why CSP Matters Content Security Policy (CSP) is a security feature that helps prevent: - Cross-Site Scripting (XSS) attacks - Data injection attacks - Unauthorized script execution Inline scripts are considered unsafe because an attacker who manages to inject HTML can also inject malicious JavaScript. CSP-compliant apps use `script-src 'self'` which blocks inline scripts. Documentation: [Content Security Policy](https://ui5.sap.com/#/topic/fe1a6dba940e479fb7c3bc753f92b28c) ## Detection The linter flags ` ``` **Not flagged:** ```html ``` ## Fix Strategy The fix for every inline script is the same: **move it to an external file and add a ` ``` **Fix Strategy**: Move inline scripts to external files. ```html My App ``` ```javascript // config.js window.myConfig = { apiUrl: "/api/v1", debug: true }; ``` ```javascript // my/app/init.js sap.ui.define([], function() { "use strict"; return { start: function() { // Initialization code } }; }); ``` ### 2. UI5 Bootstrap with Inline Init → data-sap-ui-on-init **Problem**: Inline script after UI5 bootstrap. ```html ``` **Fix Strategy**: Use `data-sap-ui-on-init` attribute. ```html ``` ```javascript // webapp/init.js sap.ui.define([ "sap/m/Shell", "sap/ui/core/ComponentContainer" ], function(Shell, ComponentContainer) { "use strict"; new Shell({ app: new ComponentContainer({ name: "my.app", async: true }) }).placeAt("content"); }); ``` ### 3. Configuration Data → JSON or Module **Problem**: Inline configuration object. ```html ``` **Fix Strategy A**: External JSON file loaded at runtime. ```html ``` ```javascript // config.js - loads JSON (function() { var xhr = new XMLHttpRequest(); xhr.open("GET", "config.json", false); // Sync for config xhr.send(); window.APP_CONFIG = JSON.parse(xhr.responseText); })(); ``` ```json // config.json { "apiEndpoint": "https://api.example.com", "features": { "darkMode": true, "analytics": false } } ``` **Fix Strategy B**: UI5 module with configuration. ```javascript // my/app/config.js sap.ui.define([], function() { "use strict"; return { apiEndpoint: "https://api.example.com", features: { darkMode: true, analytics: false } }; }); // Usage in other modules sap.ui.define(["my/app/config"], function(config) { console.log(config.apiEndpoint); }); ``` ### 4. Inline Event Handlers → External Scripts **Problem**: Inline event handlers in HTML attributes. ```html ``` **Fix Strategy**: Use external script with event listeners. ```html ``` ```javascript // app.js document.addEventListener("DOMContentLoaded", function() { document.getElementById("myButton").addEventListener("click", handleClick); document.getElementById("logo").addEventListener("error", function() { handleError(this); }); init(); }); function handleClick() { // Click handler } function handleError(element) { // Error handler } function init() { // Initialization } ``` ### 5. Test HTML Files **Problem**: QUnit test files with inline scripts. ```html
``` **Fix Strategy**: Use Test Starter (also fixes `prefer-test-starter`). ```html
``` ### 6. Dynamic Script Content **Problem**: Script content generated dynamically. ```html ``` **Fix Strategy**: Use data attributes or meta tags. ```html ``` ```javascript // app.js var userId = document.querySelector('meta[name="user-id"]').content; var token = document.querySelector('meta[name="csrf-token"]').content; ``` ## Implementation Steps 1. **Identify all inline scripts** from linter output 2. **Categorize each script**: - UI5 initialization → Use `data-sap-ui-on-init` - Configuration → External JS file - Event handlers → External script with `addEventListener` - Test boilerplate → Use Test Starter 3. **Create external files** for the script content 4. **Update HTML** to reference external files 5. **Test the application** to ensure functionality is preserved ## Common Patterns | Inline Pattern | CSP-Compliant Solution | |----------------|------------------------| | `` | `