Skip to content

Add support to restrict @Core.AcceptableMediaTypes#732

Open
samyuktaprabhu wants to merge 7 commits intomainfrom
sam-restrict-media-types-409
Open

Add support to restrict @Core.AcceptableMediaTypes#732
samyuktaprabhu wants to merge 7 commits intomainfrom
sam-restrict-media-types-409

Conversation

@samyuktaprabhu
Copy link
Contributor

@samyuktaprabhu samyuktaprabhu commented Feb 11, 2026

Add Support to Restrict @Core.AcceptableMediaTypes

✨ New Features

Introduced support for restricting allowed MIME types for attachments using the @Core.AcceptableMediaTypes annotation. This feature enables validation of file types during upload at HandlerOrder.BEFORE, ensuring only specified media types are accepted before processing begins.

🔧 Changes

Core Implementation

  • CreateAttachmentsHandler.java: Added new @Before handler method processBeforeForMetadata that validates acceptable media types early in the request lifecycle. Updated constructor to accept CdsRuntime parameter for metadata validation support.

  • AttachmentValidationHelper.java (new): Comprehensive helper class for media type validation with support for wildcard patterns (image/*) and default fallback behavior (*/*). Validates file types against configured acceptable media types.

  • MediaTypeResolver.java (new): Extracts acceptable media types from CDS entity annotations, handling both direct media entities and composed attachments using the AssociationCascader.

  • MediaTypeService.java (new): Provides MIME type resolution from file extensions using Java's URLConnection.getFileNameMap() and validates against acceptable media types with support for exact matches and wildcard patterns.

  • AttachmentDataExtractor.java (new): Extracts and validates file names from attachment data using CdsDataProcessor, ensuring files have proper extensions before MIME type validation.

  • Registration.java: Updated handler registration to pass CdsRuntime instance to CreateAttachmentsHandler.

  • ApplicationHandlerHelper.java: Added deepSearchForAttachments() method functionality (refactored into AssociationCascader).

  • AssociationCascader.java: Enhanced with hasAttachmentPath() and findMediaEntityNames() methods to recursively check for attachment compositions in entity hierarchies and collect media entity names.

Documentation

  • README.md: Added comprehensive documentation section "Restrict allowed MIME types" with examples of:
    • Exact matches (image/jpeg, image/png)
    • Wildcard patterns (image/*)
    • Default behavior (*/*)
    • Usage scenarios for single and multiple media types

Test Suite

  • CreateAttachmentsHandlerTest.java: Added tests for new metadata validation handler with proper annotation verification

  • AttachmentValidationHelperTest.java (new): Comprehensive test suite with 16+ test cases covering MIME type detection, validation, wildcards, error scenarios, and edge cases including hidden files

  • MediaTypeResolverTest.java (new): Tests for media type extraction from entity annotations

  • MediaTypeServiceTest.java (new): Tests for MIME type resolution and validation logic including edge cases like hidden files (.gitignore)

  • MediaValidatedAttachmentsDraftTest.java (new): Integration tests for draft service media validation with parameterized tests for various file types

  • MediaValidatedAttachmentsNonDraftTest.java (new): Integration tests for non-draft service media validation, including deep create scenarios and multiple attachment validation

  • AssociationCascaderTest.java: Added tests for new hasAttachmentPath() and findMediaEntityNames() methods

  • Size validation tests: Updated to include fileName assignments for proper validation

Integration Test Configuration

  • data-model.cds: Added mediaValidatedAttachments and mimeValidatedAttachments compositions to Roots entity

  • test-service.cds: Configured annotations to accept only JPEG and PNG images for mediaValidatedAttachments, and PDFs for mimeValidatedAttachments

  • RootEntityBuilder.java: Enhanced builder to initialize sizeLimitedAttachments list in constructor for proper entity setup

Sample Application

  • samples/bookshop/srv/attachments.cds:
    • Added mediaValidatedAttachments composition to Books entity
    • Configured to accept only JPEG and PNG images
    • Added UI annotations to hide the field from Browse Books App
  • 🔄 Regenerate and Update Summary

📬 Subscribe to the Hyperspace PR Bot DL to get the latest announcements and pilot features!

PR Bot Information

Version: 1.17.80 | 📖 Documentation | 🚨 Create Incident | 💬 Feedback

  • LLM: anthropic--claude-4.5-sonnet
  • Summary Prompt: Default Prompt
  • Output Template: Default Template
  • Event Trigger: pull_request.edited
  • Correlation ID: 27d010e0-1609-11f1-9c18-5f2e249083ea

Copy link
Contributor

@hyperspace-insights hyperspace-insights bot left a comment

Choose a reason for hiding this comment

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

The PR adds media type restriction support for attachments. I've identified a few issues: a typo in MIME type definitions (application/txt should be text/plain), potential security concerns with filename validation (missing path traversal checks), and a minor note about null handling. Overall the implementation is reasonable but needs these corrections before merging.

PR Bot Information

Version: 1.17.53 | 📖 Documentation | 🚨 Create Incident | 💬 Feedback

  • Event Trigger: pull_request.opened
  • LLM: anthropic--claude-4.5-sonnet
  • Correlation ID: 78c854a0-0757-11f1-833c-299ee35f3dc8

@samyuktaprabhu samyuktaprabhu changed the title Add support to restrict media types Add support to restrict @Core.AcceptableMediaTypes Feb 11, 2026
@samyuktaprabhu samyuktaprabhu force-pushed the sam-restrict-media-types-409 branch from 8b6c095 to a12bc05 Compare February 17, 2026 08:35
@samyuktaprabhu samyuktaprabhu self-assigned this Feb 17, 2026
Copy link
Contributor

@hyperspace-insights hyperspace-insights bot left a comment

Choose a reason for hiding this comment

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


Summary

The pull request introduces MIME type validation for attachments with good test coverage. However, several null safety issues were identified in the validation logic that could lead to NullPointerException errors. Additionally, a minor CDS syntax inconsistency and a misleading test variable name should be addressed.

PR Bot Information

Version: 1.17.61 | 📖 Documentation | 🚨 Create Incident | 💬 Feedback

  • Event Trigger: issue_comment.created
  • Correlation ID: b7b79080-0bdb-11f1-9b97-78cdc3653ab1
  • LLM: anthropic--claude-4.5-sonnet

@hyperspace-insights hyperspace-insights bot deleted a comment from samyuktaprabhu Feb 17, 2026
@samyuktaprabhu samyuktaprabhu marked this pull request as ready for review February 17, 2026 08:36
@samyuktaprabhu samyuktaprabhu force-pushed the sam-restrict-media-types-409 branch from e2b000e to 26b499c Compare February 17, 2026 09:36
Copy link
Collaborator

@Schmarvinius Schmarvinius left a comment

Choose a reason for hiding this comment

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

Unit-Tests:

  • AttachmentCalidationHelperTest:
    • Add a test for wildcard subtype rejection like image/* should reject application/pdf
    • Add a test for files start with . like .gitignore or .ssh or .zshrc and so on

Integration-Tests:

  • MediaCalidatedAttachmentsDraftTest:
    • Add a test for false inputs like an empty string. You have them for non draft but not for draft.
    • Add tests for situations where it fails like upload a pdf when only jpeg or image/* is allowed
      • Also one for dotfiles
  • MediaValidatedAttachmentsNonDraftTest:
    • Add a test for case sensitivity in the extension
    • Add a test for no extension
    • Add a test for hidden files again

@samyuktaprabhu samyuktaprabhu force-pushed the sam-restrict-media-types-409 branch from 3df6d49 to e98f840 Compare February 25, 2026 08:40
Copy link
Contributor

@hyperspace-insights hyperspace-insights bot left a comment

Choose a reason for hiding this comment

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

Summary

This PR introduces MIME type validation for attachments with generally solid implementation. I've identified 9 substantive issues requiring attention:

  • Critical: Missing file extension validation in MediaTypeService.resolveMimeType() could cause runtime errors
  • Important: Inconsistent filename validation between extractor and validator creates confusing error paths
  • Security consideration: FileNameValidator doesn't check for path traversal characters (e.g., ../, null bytes)
  • Several performance and code quality improvements around duplicate constants, inefficient stream operations, and wildcard matching logic

The test coverage is comprehensive, and the feature design is well-thought-out. Address the validation and error-handling gaps before merging.

PR Bot Information

Version: 1.17.72 | 📖 Documentation | 🚨 Create Incident | 💬 Feedback

  • LLM: anthropic--claude-4.5-sonnet
  • Event Trigger: issue_comment.created
  • Correlation ID: a7941f80-1242-11f1-91ae-db28216a7610

@hyperspace-insights hyperspace-insights bot deleted a comment from samyuktaprabhu Feb 25, 2026
Copy link
Collaborator

@Schmarvinius Schmarvinius left a comment

Choose a reason for hiding this comment

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

I think your whole structe has gotten very complicated.
Why don't you merge FileNameValidator + MediaTypeService + MediaTypeResolver + AttachmentValidationHelper into one MediaTypeValidator
And keep the DataExtractor as-is. This reduces complexity and keeps separation of concern to a healthy degree.

@samyuktaprabhu samyuktaprabhu marked this pull request as draft February 27, 2026 11:26
@samyuktaprabhu samyuktaprabhu marked this pull request as draft February 27, 2026 11:26
@samyuktaprabhu
Copy link
Contributor Author

I think your whole structe has gotten very complicated.
Why don't you merge FileNameValidator + MediaTypeService + MediaTypeResolver + AttachmentValidationHelper into one MediaTypeValidator
And keep the DataExtractor as-is. This reduces complexity and keeps separation of concern to a healthy degree.

Thanks for your review &suggestion. I merged FileNameValidator & AttachmentDataExtractor. I tried doing the merge for the other 3 files, but, if we do that, we'd end up making it harder to test, and also make it harder to reuse later.

@samyuktaprabhu samyuktaprabhu force-pushed the sam-restrict-media-types-409 branch from 534423e to ab8ab07 Compare February 27, 2026 19:05
…chments/configuration/Registration.java

Co-authored-by: Marvin <marvin.lindner@sap.com>

Update cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java

Co-authored-by: Marvin <marvin.lindner@sap.com>

Update cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java

Co-authored-by: Marvin <marvin.lindner@sap.com>

Update cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java

Co-authored-by: Marvin <marvin.lindner@sap.com>

apply mvnspotless:apply

Rename AttachmentDataExtractor to validation package

Refactor MediaTypeService to use URLConnection for MIME type resolution and update AttachmentValidationHelper method visibility

Refactor AttachmentValidationHelper to streamline MIME type validation logic

Add unit tests for AssociationCascader and refactor AttachmentValidationHelper and MediaTypeResolver to utilize AssociationCascader for media entity resolution

Refactor MediaTypeResolver to remove dependency on ApplicationHandlerHelper and update related tests

Refactor file name validation logic and migrate to mimeTypeValidation package

Refactor AttachmentDataExtractor to integrate filename validation logic and remove FileNameValidator class

Refactor AttachmentDataExtractor and update tests to improve structure and maintainability

Refactor AttachmentValidationHelper and MediaTypeResolver to improve structure and add unit tests for media type resolution

revert a change
@samyuktaprabhu samyuktaprabhu force-pushed the sam-restrict-media-types-409 branch from 46592c3 to c458640 Compare February 27, 2026 19:07
@samyuktaprabhu samyuktaprabhu marked this pull request as ready for review March 2, 2026 07:25
Copy link
Collaborator

@Schmarvinius Schmarvinius left a comment

Choose a reason for hiding this comment

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

Just noticed: do you cover PATCHING/Updating a Root entity when adding attachments?

});
}

private static String fallbackToDefaultMimeType(String fileName) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is an extra function needed?

Comment on lines +57 to +59
if (acceptableMediaTypes == null
|| acceptableMediaTypes.isEmpty()
|| acceptableMediaTypes.contains("*/*")) return true;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if (acceptableMediaTypes == null
|| acceptableMediaTypes.isEmpty()
|| acceptableMediaTypes.contains("*/*")) return true;
if (acceptableMediaTypes == null || acceptableMediaTypes.isEmpty()) {
return true;
}
if (acceptableMediaTypes.stream().anyMatch(type -> type.trim().toLowerCase().equals("*/*"))) {
return true;
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

The contains("/") check runs on the raw annotation values before normalization (trim().toLowerCase()), so a value like " / " with surrounding whitespace would fail to short-circuit as a wildcard. Consider normalizing first, or moving this check after normalization.

Comment on lines +42 to +54
boolean areAttachmentsAvailable =
ApplicationHandlerHelper.isMediaEntity(entity)
|| cascader.hasAttachmentPath(cdsModel, entity);

if (!areAttachmentsAvailable) {
return;
}

// validate the media types of the attachments
Map<String, List<String>> allowedTypesByElementName =
MediaTypeResolver.getAcceptableMediaTypesFromEntity(entity, cdsModel);
Map<String, Set<String>> fileNamesByElementName =
AttachmentDataExtractor.extractAndValidateFileNamesByElement(entity, data);
Copy link
Collaborator

Choose a reason for hiding this comment

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

hasAttachmentPath and findMediaEntityNames both internally call findEntityPath, so the entity tree is traversed twice per request. You could avoid this by calling findMediaEntityNames once and using its result to determine both conditions

Comment on lines +67 to +78
private static String validateAndNormalize(String fileName) {
String trimmedFileName = fileName.trim();
if (trimmedFileName.isEmpty()) {
throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Filename must not be blank");
}

int lastDotIndex = trimmedFileName.lastIndexOf('.');
if (lastDotIndex == -1 || lastDotIndex == trimmedFileName.length() - 1) {
throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid filename format: " + fileName);
}
return trimmedFileName;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

validateAndNormalize throws BAD_REQUEST when a filename has no extension, while MediaTypeService.resolveMimeType handles the same case by falling back to a default MIME type (application/octet-stream). Since validateAndNormalize runs first in the flow, the fallback in resolveMimeType is unreachable for this code path.

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.

2 participants