Conversation
…nguage, structure, and flow. Optimize headings and enhance content for improved readability and engagement.
…end JSON handling for AI responses with improved validation and single-element array unwrapping. Integrate MD-viewer in retrospective UI for better rendering. Extend DocController with fallback logic for task filenames.
|
|
||
| // Ensure requested path is within base directory | ||
| if (!requestedPath.startsWith(basePath)) { | ||
| log.warn("Potential path traversal attempt: {}", path); |
Check failure
Code scanning / CodeQL
Log Injection High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 8 hours ago
To fix the problem, sanitize the user-controlled path value before including it in log messages. The main goal is to prevent newlines and other control characters from breaking the log format or creating the impression of multiple entries, while still preserving enough information for debugging.
The best low-impact fix here is to create a sanitized version of path that strips or replaces newline (\n) and carriage-return (\r) characters (and optionally trims the result), and then log that sanitized value instead of the raw input. We can do this locally in the method without introducing new dependencies or changing behavior elsewhere.
Concretely, in DocController.getRawDoc at the path-traversal check, change:
if (!requestedPath.startsWith(basePath)) {
log.warn("Potential path traversal attempt: {}", path);
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}to compute a safe sanitizedPath and use that in the log:
if (!requestedPath.startsWith(basePath)) {
String sanitizedPath = path.replace('\n', '_')
.replace('\r', '_');
log.warn("Potential path traversal attempt: {}", sanitizedPath);
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}This keeps the logging behavior (including the user-provided content) but prevents an attacker from injecting line breaks into the log. No new imports or methods are strictly required; the sanitization can be done inline where the log call occurs.
| @@ -62,7 +62,8 @@ | ||
|
|
||
| // Ensure requested path is within base directory | ||
| if (!requestedPath.startsWith(basePath)) { | ||
| log.warn("Potential path traversal attempt: {}", path); | ||
| String sanitizedPath = path.replace('\n', '_').replace('\r', '_'); | ||
| log.warn("Potential path traversal attempt: {}", sanitizedPath); | ||
| return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); | ||
| } | ||
|
|
|
|
||
| // Restrict access to doc/ directory or allowed root files | ||
| if (!relativePathStr.startsWith("doc/") && !ALLOWED_ROOT_FILES.contains(relativePathStr)) { | ||
| log.warn("Access denied to non-documentation file: {}", path); |
Check failure
Code scanning / CodeQL
Log Injection High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 8 hours ago
In general terms, to fix log injection you must ensure that any user-provided data is sanitized before being written to logs. For plain-text logs, that usually means removing or replacing newline and carriage-return characters and potentially other control characters, then logging the sanitized value instead of the raw input.
In this specific case, the fix is to avoid logging the raw path parameter and instead log a sanitized variant that cannot break log lines. The simplest, non-functional-change option is to create a sanitized version of path just for logging. For example, we can define a local variable such as String safePathForLog = path.replace('\n', '_').replace('\r', '_'); and then use safePathForLog in the log statements. This keeps all program behavior (file resolution, permission checks, responses) identical, while ensuring that the log output cannot contain raw line breaks from user input. To avoid duplicating logic, we can define this once near the top of getRawDoc (after the method signature) and reuse it in all log calls that include path (lines 97, 127, and 131). No new imports are needed, as String.replace is part of the standard library and String is already in scope.
Concretely:
- In
getRawDoc, add a local variable right at the start of thetryblock (or just after the method begins) computing a log-safe version of the request parameter:String safePathForLog = path.replace('\n', '_').replace('\r', '_');. - Change the log statements that currently interpolate
path(log.warnon line 97,log.warnon line 127, andlog.erroron line 131) to usesafePathForLoginstead. - The rest of the logic that relies on the original
pathshould remain unchanged.
| @@ -44,6 +44,7 @@ | ||
| @GetMapping("/raw") | ||
| public ResponseEntity<String> getRawDoc(@RequestParam String path) { | ||
| try { | ||
| String safePathForLog = path.replace('\n', '_').replace('\r', '_'); | ||
| // Strip fragments if present (e.g. #section) | ||
| String cleanPath = path; | ||
| if (path.contains("#")) { | ||
| @@ -94,7 +95,7 @@ | ||
|
|
||
| // Restrict access to doc/ directory or allowed root files | ||
| if (!relativePathStr.startsWith("doc/") && !ALLOWED_ROOT_FILES.contains(relativePathStr)) { | ||
| log.warn("Access denied to non-documentation file: {}", path); | ||
| log.warn("Access denied to non-documentation file: {}", safePathForLog); | ||
| return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); | ||
| } | ||
|
|
||
| @@ -124,11 +125,11 @@ | ||
| .contentType(MediaType.TEXT_PLAIN) | ||
| .body(content); | ||
| } else { | ||
| log.warn("File not found or not readable: {}", path); | ||
| log.warn("File not found or not readable: {}", safePathForLog); | ||
| return ResponseEntity.notFound().build(); | ||
| } | ||
| } catch (IOException e) { | ||
| log.error("Error reading doc file: {}", path, e); | ||
| log.error("Error reading doc file: {}", safePathForLog, e); | ||
| return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); | ||
| } | ||
| } |
| if (found.isPresent()) { | ||
| requestedPath = found.get(); | ||
| resource = new UrlResource(requestedPath.toUri()); | ||
| log.info("Resolved partial task path {} to {}", path, requestedPath); |
Check failure
Code scanning / CodeQL
Log Injection High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 8 hours ago
In general, to fix log injection issues, ensure that any user-controlled string is sanitized before being written to logs. For plain-text logs, this typically means removing or replacing newline (\n), carriage return (\r), and other control characters so that one log call cannot visually become multiple entries or alter log formatting.
For this specific code, the minimal, non-functional change is to sanitize the path parameter only for logging, leaving the original path value untouched for functional use. We can create a local sanitized variable that strips \r and \n characters from path right before the log.info call, and use that sanitized variable in the log message. This keeps the business logic (file resolution, etc.) unchanged and only affects what is written into logs.
Concretely:
- In
DocController.getRawDoc, locate thelog.info("Resolved partial task path {} to {}", path, requestedPath);line (around line 114). - Immediately before this log line, introduce a new local variable, e.g.
String safePathForLog = path.replace('\n', '_').replace('\r', '_');. - Update the
log.infocall to usesafePathForLoginstead of the rawpath. - No new imports are needed, as
String.replaceis part of the standard library.
| @@ -111,7 +111,8 @@ | ||
| if (found.isPresent()) { | ||
| requestedPath = found.get(); | ||
| resource = new UrlResource(requestedPath.toUri()); | ||
| log.info("Resolved partial task path {} to {}", path, requestedPath); | ||
| String safePathForLog = path.replace('\n', '_').replace('\r', '_'); | ||
| log.info("Resolved partial task path {} to {}", safePathForLog, requestedPath); | ||
| } | ||
| } | ||
| } |
| if (found.isPresent()) { | ||
| requestedPath = found.get(); | ||
| resource = new UrlResource(requestedPath.toUri()); | ||
| log.info("Resolved partial task path {} to {}", path, requestedPath); |
Check failure
Code scanning / CodeQL
Log Injection High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 8 hours ago
To fix this, user-controlled data should be sanitized or constrained before being written to the log. For log injection, the primary concern is stripping or neutralizing newline (\n, \r) and similar control characters so that a single log entry cannot be split into multiple lines. A typical pattern is to define a small helper method that takes a String (or Object) and returns a sanitized version with problematic characters removed or replaced.
The best minimal-impact fix here is:
- Introduce a private helper method in
DocController, for examplesanitizeForLogging(String input), that removes carriage returns and newlines (and optionally other non-printable control characters). - Use that helper when logging both the original
pathand any derived values (likerequestedPath) that originate from user input. In the specific flagged line, changerequestedPathtosanitizeForLogging(requestedPath.toString()). Similarly, for the other logging lines that directly logpath, wrappathwith the same sanitizer. - This keeps the existing functionality (log messages and control flow) intact while ensuring logged values cannot introduce injected newlines.
Concretely in backend/src/main/java/ch/goodone/backend/controller/DocController.java:
- Add the helper method near the top of the class (e.g. after the
baseDirfield). - Update:
- line 65:
"Potential path traversal attempt: {}", path→ usesanitizeForLogging(path) - line 114:
"Resolved partial task path {} to {}", path, requestedPath→ usesanitizeForLogging(path)andsanitizeForLogging(requestedPath.toString()) - line 127:
"File not found or not readable: {}", path→ usesanitizeForLogging(path) - line 131:
"Error reading doc file: {}", path, e→ usesanitizeForLogging(path)
- line 65:
No new external dependencies are needed; the sanitizer can be implemented with basic String operations.
| @@ -36,6 +36,19 @@ | ||
| private String baseDir; | ||
|
|
||
| /** | ||
| * Sanitize a value before logging to prevent log injection. | ||
| * Removes carriage returns and newlines to avoid forged log entries. | ||
| */ | ||
| private String sanitizeForLogging(String value) { | ||
| if (value == null) { | ||
| return null; | ||
| } | ||
| // Remove CR and LF characters; additional control chars can be stripped if needed | ||
| return value.replace('\r', ' ') | ||
| .replace('\n', ' '); | ||
| } | ||
|
|
||
| /** | ||
| * Retrieve the raw content of a documentation file. | ||
| * | ||
| * @param path The path to the documentation file (relative to the base directory). | ||
| @@ -62,7 +75,7 @@ | ||
|
|
||
| // Ensure requested path is within base directory | ||
| if (!requestedPath.startsWith(basePath)) { | ||
| log.warn("Potential path traversal attempt: {}", path); | ||
| log.warn("Potential path traversal attempt: {}", sanitizeForLogging(path)); | ||
| return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); | ||
| } | ||
|
|
||
| @@ -111,7 +124,7 @@ | ||
| if (found.isPresent()) { | ||
| requestedPath = found.get(); | ||
| resource = new UrlResource(requestedPath.toUri()); | ||
| log.info("Resolved partial task path {} to {}", path, requestedPath); | ||
| log.info("Resolved partial task path {} to {}", sanitizeForLogging(path), sanitizeForLogging(requestedPath.toString())); | ||
| } | ||
| } | ||
| } | ||
| @@ -124,11 +137,11 @@ | ||
| .contentType(MediaType.TEXT_PLAIN) | ||
| .body(content); | ||
| } else { | ||
| log.warn("File not found or not readable: {}", path); | ||
| log.warn("File not found or not readable: {}", sanitizeForLogging(path)); | ||
| return ResponseEntity.notFound().build(); | ||
| } | ||
| } catch (IOException e) { | ||
| log.error("Error reading doc file: {}", path, e); | ||
| log.error("Error reading doc file: {}", sanitizeForLogging(path), e); | ||
| return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); | ||
| } | ||
| } |
| .contentType(MediaType.TEXT_PLAIN) | ||
| .body(content); | ||
| } else { | ||
| log.warn("File not found or not readable: {}", path); |
Check failure
Code scanning / CodeQL
Log Injection High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 8 hours ago
In general, to fix log injection, any user-controlled values logged should be sanitized before logging: at minimum, remove or neutralize newline and carriage-return characters and optionally other non-printable control characters. This avoids a situation where user input can break the log entry format and appear as separate entries or inject misleading content.
The best targeted fix here is to sanitize the path value once when it is received and then use the sanitized version both for logging and (optionally) for further processing if we want consistency. Since we must not change behavior beyond security, the safest minimal change is to introduce a small helper method in DocController that strips \r and \n (and optionally other control characters) from strings before they are logged, then wrap uses of path in the log statements with this helper, while leaving all other logic unchanged. No new external dependencies are needed; standard Java is sufficient.
Concretely, in backend/src/main/java/ch/goodone/backend/controller/DocController.java:
- Add a private static helper method, e.g.
sanitizeForLog(String input), that:- Returns
nullif input isnull. - Replaces
\rand\nwith a safe placeholder (e.g. a space) or removes them. - Optionally removes any other ISO control characters using
StringBuilderandCharacter.isISOControl.
- Returns
- Update
log.warn("File not found or not readable: {}", path);to logsanitizeForLog(path)instead. - Update
log.error("Error reading doc file: {}", path, e);similarly.
This keeps the functional meaning of the logs (the path value) while preventing multi-line or control-character injection.
| @@ -36,6 +36,30 @@ | ||
| private String baseDir; | ||
|
|
||
| /** | ||
| * Sanitize potentially untrusted text before logging to avoid log injection. | ||
| * | ||
| * This removes newline and carriage-return characters and other ISO control characters | ||
| * that could be used to forge or confuse log entries. | ||
| */ | ||
| private static String sanitizeForLog(String input) { | ||
| if (input == null) { | ||
| return null; | ||
| } | ||
| StringBuilder sb = new StringBuilder(input.length()); | ||
| for (int i = 0; i < input.length(); i++) { | ||
| char c = input.charAt(i); | ||
| if (c == '\r' || c == '\n') { | ||
| // Replace line breaks with a space to keep readability. | ||
| sb.append(' '); | ||
| } else if (!Character.isISOControl(c)) { | ||
| sb.append(c); | ||
| } | ||
| // Other control characters are skipped entirely. | ||
| } | ||
| return sb.toString(); | ||
| } | ||
|
|
||
| /** | ||
| * Retrieve the raw content of a documentation file. | ||
| * | ||
| * @param path The path to the documentation file (relative to the base directory). | ||
| @@ -124,11 +148,11 @@ | ||
| .contentType(MediaType.TEXT_PLAIN) | ||
| .body(content); | ||
| } else { | ||
| log.warn("File not found or not readable: {}", path); | ||
| log.warn("File not found or not readable: {}", sanitizeForLog(path)); | ||
| return ResponseEntity.notFound().build(); | ||
| } | ||
| } catch (IOException e) { | ||
| log.error("Error reading doc file: {}", path, e); | ||
| log.error("Error reading doc file: {}", sanitizeForLog(path), e); | ||
| return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); | ||
| } | ||
| } |
| return ResponseEntity.notFound().build(); | ||
| } | ||
| } catch (IOException e) { | ||
| log.error("Error reading doc file: {}", path, e); |
Check failure
Code scanning / CodeQL
Log Injection High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 8 hours ago
In general, to fix log injection, any user-controlled value that is written to logs should be sanitized or validated beforehand. Commonly, this means either (a) validating the value against an allowlist of acceptable characters (for example, only alphanumerics, some punctuation, and path separators) or (b) normalizing/removing dangerous characters such as line breaks and other control characters before logging. The main goal is to prevent an attacker from injecting additional log lines or manipulating the structure/semantics of log entries.
For this specific case, the best minimal fix that does not change existing behavior is to sanitize path only for logging, while leaving the original path untouched for application logic. We can do this by creating a sanitized copy (e.g., String safePathForLog = sanitizeForLogging(path);) right before logging and passing that to log.warn and log.error. The sanitization should at least strip carriage returns and newlines, and ideally other control characters, while keeping regular visible characters unchanged. Since we must keep the change localized to this file and code, we can implement a small private helper method sanitizeForLogging(String value) inside DocController that removes \r, \n, and other ISO control characters from the string, and use it in the two log statements that currently log raw path. No new external dependencies are needed; we can implement this with core Java (StringBuilder, Character.isISOControl). Concretely, in getRawDoc, update line 127 and 131 to log sanitizeForLogging(path) instead of path, and add the helper method inside DocController (e.g., near the bottom of the class).
| @@ -124,12 +124,34 @@ | ||
| .contentType(MediaType.TEXT_PLAIN) | ||
| .body(content); | ||
| } else { | ||
| log.warn("File not found or not readable: {}", path); | ||
| log.warn("File not found or not readable: {}", sanitizeForLogging(path)); | ||
| return ResponseEntity.notFound().build(); | ||
| } | ||
| } catch (IOException e) { | ||
| log.error("Error reading doc file: {}", path, e); | ||
| log.error("Error reading doc file: {}", sanitizeForLogging(path), e); | ||
| return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Sanitize potentially user-controlled input before logging to prevent log injection. | ||
| * Removes control characters such as newlines and carriage returns while leaving | ||
| * printable characters intact. | ||
| * | ||
| * @param value the original value, may be {@code null} | ||
| * @return a sanitized representation safe for logging | ||
| */ | ||
| private String sanitizeForLogging(String value) { | ||
| if (value == null) { | ||
| return null; | ||
| } | ||
| StringBuilder sb = new StringBuilder(value.length()); | ||
| for (int i = 0; i < value.length(); i++) { | ||
| char c = value.charAt(i); | ||
| if (!Character.isISOControl(c)) { | ||
| sb.append(c); | ||
| } | ||
| } | ||
| return sb.toString(); | ||
| } | ||
| } |
Qodana Community for JVMIt seems all right 👌 No new problems were found according to the checks applied 💡 Qodana analysis was run in the pull request mode: only the changed files were checked View the detailed Qodana reportTo be able to view the detailed Qodana report, you can either:
To get - name: 'Qodana Scan'
uses: JetBrains/qodana-action@v2024.3.4
with:
upload-result: trueContact Qodana teamContact us at qodana-support@jetbrains.com
|
…Add feature for better null handling and link navigation, including bug fixes and translation support.
…ment by streamlining structure, language, and flow. Optimize headings and adjust sections for consistency.
…hance Markdown viewer to handle ADR anchors, lists correctly. Add tests for the updated markdown viewer and create new tests for HelpContentComponent.
| @@ -0,0 +1,144 @@ | |||
| import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; | |||
| import { HelpContentComponent } from './help-content.component'; | |||
| import { ActivatedRoute, Router } from '@angular/router'; | |||
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 18 hours ago
To fix the problem, the unused Router import should be removed so that only the actually used symbol(s) are imported from @angular/router. This keeps the test file cleaner and avoids confusion about dependencies.
Concretely, in frontend/src/app/components/help/help-content.component.spec.ts, adjust the import on line 3 to remove Router, leaving only ActivatedRoute. No other code changes are required because Router is not referenced anywhere else in the snippet. No additional methods, imports, or definitions are needed.
| @@ -1,6 +1,6 @@ | ||
| import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; | ||
| import { HelpContentComponent } from './help-content.component'; | ||
| import { ActivatedRoute, Router } from '@angular/router'; | ||
| import { ActivatedRoute } from '@angular/router'; | ||
| import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; | ||
| import { RouterTestingModule } from '@angular/router/testing'; | ||
| import { TranslateModule } from '@ngx-translate/core'; |
| import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; | ||
| import { RouterTestingModule } from '@angular/router/testing'; | ||
| import { TranslateModule } from '@ngx-translate/core'; | ||
| import { Subject, of } from 'rxjs'; |
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 18 hours ago
In general, unused imports should be removed from the file to avoid confusion and keep the code clean. When multiple symbols are imported from the same module, remove only those that are not referenced anywhere in the file, keeping the ones that are used.
In this case, the best fix is to adjust the rxjs import on line 7 in frontend/src/app/components/help/help-content.component.spec.ts so that it only imports Subject, which is used to create paramsSubject and fragmentSubject. The symbol of should be removed from the curly-brace import list. No additional methods, imports, or definitions are required.
| @@ -4,7 +4,7 @@ | ||
| import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; | ||
| import { RouterTestingModule } from '@angular/router/testing'; | ||
| import { TranslateModule } from '@ngx-translate/core'; | ||
| import { Subject, of } from 'rxjs'; | ||
| import { Subject } from 'rxjs'; | ||
| import { I18nService } from '../../services/i18n.service'; | ||
| import { NoopAnimationsModule } from '@angular/platform-browser/animations'; | ||
| import { vi } from 'vitest'; |
… traceability across components.
| requestedPath = found.get(); | ||
| resource = new UrlResource(requestedPath.toUri()); | ||
| relativePathStr = basePath.relativize(requestedPath).toString().replace('\\', '/'); | ||
| log.info("Resolved task ID {} to {}", searchPath, requestedPath); |
Check failure
Code scanning / CodeQL
Log Injection High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 8 hours ago
To fix the problem, sanitize the user-controlled string before logging it. For plain-text logs, the minimum is to remove or normalize line breaks and other control characters so a user cannot inject extra log entries or manipulate log structure. We can do this locally, just before logging, without changing any functional behavior.
The best targeted fix here is:
- Introduce a small private helper method in
DocControllerthat takes aStringand returns a sanitized version with\rand\nremoved (and optionally other control characters). - Use this helper when logging
searchPathandpathso that any CR/LF characters supplied by the user cannot create forged log lines. - Keep the original values for all non-logging logic (path traversal checks, file resolution, etc.) so behavior of the endpoint is unchanged except for log safety.
Concretely, in backend/src/main/java/ch/goodone/backend/controller/DocController.java:
- Add a private method, e.g.
sanitizeForLog, near the top of the class (just after the fields), which:- Returns
nullif the input isnull. - Replaces
\rand\nwith spaces (or removes them).
- Returns
- Update line 89 to log
sanitizeForLog(searchPath)instead ofsearchPath. - Optionally (but recommended for consistency and defense-in-depth), also update lines 65 and 97 to log
sanitizeForLog(path).
No new imports are needed; String.replace is in java.lang.
| @@ -36,6 +36,20 @@ | ||
| private String baseDir; | ||
|
|
||
| /** | ||
| * Sanitize a string for safe logging by removing line breaks. | ||
| * | ||
| * @param value the original string | ||
| * @return a sanitized string safe for logging | ||
| */ | ||
| private String sanitizeForLog(String value) { | ||
| if (value == null) { | ||
| return null; | ||
| } | ||
| // Remove CR and LF characters to prevent log forging via new lines | ||
| return value.replace('\r', ' ').replace('\n', ' '); | ||
| } | ||
|
|
||
| /** | ||
| * Retrieve the raw content of a documentation file. | ||
| * | ||
| * @param path The path to the documentation file (relative to the base directory). | ||
| @@ -62,7 +76,7 @@ | ||
|
|
||
| // Ensure requested path is within base directory | ||
| if (!requestedPath.startsWith(basePath)) { | ||
| log.warn("Potential path traversal attempt: {}", path); | ||
| log.warn("Potential path traversal attempt: {}", sanitizeForLog(path)); | ||
| return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); | ||
| } | ||
|
|
||
| @@ -86,7 +100,7 @@ | ||
| requestedPath = found.get(); | ||
| resource = new UrlResource(requestedPath.toUri()); | ||
| relativePathStr = basePath.relativize(requestedPath).toString().replace('\\', '/'); | ||
| log.info("Resolved task ID {} to {}", searchPath, requestedPath); | ||
| log.info("Resolved task ID {} to {}", sanitizeForLog(searchPath), requestedPath); | ||
| } | ||
| } | ||
| } | ||
| @@ -94,7 +108,7 @@ | ||
|
|
||
| // Restrict access to doc/ directory or allowed root files | ||
| if (!relativePathStr.startsWith("doc/") && !ALLOWED_ROOT_FILES.contains(relativePathStr)) { | ||
| log.warn("Access denied to non-documentation file: {}", path); | ||
| log.warn("Access denied to non-documentation file: {}", sanitizeForLog(path)); | ||
| return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); | ||
| } | ||
|
|
||
| @@ -128,7 +142,7 @@ | ||
| return ResponseEntity.notFound().build(); | ||
| } | ||
| } catch (IOException e) { | ||
| log.error("Error reading doc file: {}", path, e); | ||
| log.error("Error reading doc file: {}", sanitizeForLog(path), e); | ||
| return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); | ||
| } | ||
| } |
| @Builder.Default | ||
| private java.util.Map<String, String> evidencePaths = new java.util.HashMap<>(); | ||
|
|
||
| public java.util.Map<String, String> getEvidencePaths() { |
Check notice
Code scanning / CodeQL
Exposing internal representation Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 8 hours ago
In general, to avoid exposing internal mutable state, getters for mutable fields should not return the underlying collection directly. Instead, they should either return an immutable/read-only view, or a defensive copy. Setters/constructors should likewise defensively copy incoming mutable arguments. For RiskItem.evidencePaths, we only need to adjust the getter so external callers cannot directly mutate the internal map.
The best minimal fix here is to make getEvidencePaths return a new HashMap containing the same entries as the internal evidencePaths field. This preserves current behavior for read access (callers still see the same key-value pairs), while ensuring that any modifications to the returned map do not affect the internal representation. We should keep the lazy-initialization behavior so existing code that expects a non-null map continues to work. No changes are needed to the field declaration or other methods, and no extra imports are required because the code already uses fully-qualified java.util classes.
Concretely, in backend/src/main/java/ch/goodone/backend/ai/dto/RiskRadarResponse.java, within the RiskItem class, update the getEvidencePaths method (lines 66–71) to:
- Ensure
evidencePathsis initialized as before if it isnull. - Return
new java.util.HashMap<>(evidencePaths)instead of returningevidencePathsdirectly.
| @@ -67,7 +67,7 @@ | ||
| if (evidencePaths == null) { | ||
| evidencePaths = new java.util.HashMap<>(); | ||
| } | ||
| return evidencePaths; | ||
| return new java.util.HashMap<>(evidencePaths); | ||
| } | ||
|
|
||
| public java.util.List<String> getEvidence() { |
UX / UI Change PR
Scope
Acceptance criteria (must be explicit)
What changed (systemic first)
Screens / viewports verified
UX Regression Checklist (must all be ✅)
Theme & contrast
mat-icon-button+ destructive actions)Mobile space & layout
Responsive patterns
Maintainability
!important(or justified below)Justifications (required if any)
!importantadded because: