@@ -779,7 +779,7 @@ class AwsBatchTaskHandler extends TaskHandler implements BatchHandler<String,Job
779
779
builder. jobQueue(getJobQueue(task))
780
780
builder. jobDefinition(getJobDefinition(task))
781
781
if ( labels ) {
782
- final tags = opts . sanitizeTags() ? sanitizeAwsBatchLabels( labels) : labels
782
+ final tags = validateAwsBatchLabels( labels)
783
783
builder. tags(tags)
784
784
builder. propagateTags(true )
785
785
}
@@ -866,76 +866,95 @@ class AwsBatchTaskHandler extends TaskHandler implements BatchHandler<String,Job
866
866
}
867
867
868
868
/**
869
- * Sanitize resource labels to comply with AWS Batch tag requirements.
870
- * AWS Batch tags have specific constraints:
871
- * - Keys and values can contain: letters, numbers, spaces, and characters: _ . : / = + - @
872
- * - Maximum key length: 128 characters
869
+ * Validate AWS Batch labels for compliance with AWS naming requirements.
870
+ * This method validates resource labels against AWS Batch tag constraints and
871
+ * handles violations based on the nextflow.enable.strict setting:
872
+ *
873
+ * - When strict mode is disabled (default): logs warnings for invalid tags but allows them through
874
+ * - When strict mode is enabled: throws ProcessUnrecoverableException for invalid tags
875
+ *
876
+ * AWS Batch tag constraints validated:
877
+ * - Keys and values cannot be null
878
+ * - Maximum key length: 128 characters
873
879
* - Maximum value length: 256 characters
880
+ * - Allowed characters: letters, numbers, spaces, and: _ . : / = + - @
874
881
*
875
882
* @param labels The original resource labels map
876
- * @return A new map with sanitized labels suitable for AWS Batch tags
883
+ * @return The labels map (unchanged in validation mode)
884
+ * @throws ProcessUnrecoverableException when strict mode is enabled and labels are invalid
877
885
*/
878
- protected Map<String , String > sanitizeAwsBatchLabels (Map<String , String > labels ) {
886
+ protected Map<String , String > validateAwsBatchLabels (Map<String , String > labels ) {
879
887
if (! labels) return labels
880
888
881
- final result = new LinkedHashMap<String , String > ()
889
+ final strictMode = executor. session. config. navigate(' nextflow.enable.strict' , false )
890
+ final violations = []
891
+ final result = new HashMap<String , String > ()
882
892
883
893
for (Map.Entry < String , String > entry : labels. entrySet()) {
884
894
final key = entry. getKey()
885
895
final value = entry. getValue()
886
896
887
- // Handle null keys or values
888
- if (key == null || value == null ) {
889
- log. warn " AWS Batch label dropped due to null ${ key == null ? 'key' : 'value' } : key=${ key } , value=${ value} "
897
+ // Check for null keys or values and filter them out (not validation violations)
898
+ if (key == null ) {
899
+ log. warn " AWS Batch label dropped due to null key: key=null , value=${ value} "
890
900
continue
891
901
}
892
-
893
- final originalKey = key. toString()
894
- final originalValue = value. toString()
895
- final sanitizedKey = sanitizeAwsBatchLabel(originalKey, 128 )
896
- final sanitizedValue = sanitizeAwsBatchLabel(originalValue, 256 )
897
-
898
- // Check if sanitization resulted in empty strings
899
- if (! sanitizedKey || ! sanitizedValue) {
900
- log. warn " AWS Batch label dropped after sanitization - key: '${ originalKey} ' -> '${ sanitizedKey ?: ''} ', value: '${ originalValue} ' -> '${ sanitizedValue ?: ''} '"
902
+ if (value == null ) {
903
+ log. warn " AWS Batch label dropped due to null value: key=${ key} , value=null"
901
904
continue
902
905
}
903
906
904
- // Log if values were modified during sanitization
905
- if (sanitizedKey != originalKey || sanitizedValue != originalValue) {
906
- log. warn " AWS Batch label sanitized - key: '${ originalKey} ' -> '${ sanitizedKey} ', value: '${ originalValue} ' -> '${ sanitizedValue} '"
907
+ final keyStr = key. toString()
908
+ final valueStr = value. toString()
909
+
910
+ // Validate key length
911
+ if (keyStr. length() > 128 ) {
912
+ violations << " Label key exceeds 128 characters: '${ keyStr} ' (${ keyStr.length()} chars)"
913
+ }
914
+
915
+ // Validate value length
916
+ if (valueStr. length() > 256 ) {
917
+ violations << " Label value exceeds 256 characters: '${ keyStr} ' = '${ valueStr} ' (${ valueStr.length()} chars)"
918
+ }
919
+
920
+ // Validate key characters
921
+ if (! isValidAwsBatchTagString(keyStr)) {
922
+ violations << " Label key contains invalid characters: '${ keyStr} ' - only letters, numbers, spaces, and _ . : / = + - @ are allowed"
923
+ }
924
+
925
+ // Validate value characters
926
+ if (! isValidAwsBatchTagString(valueStr)) {
927
+ violations << " Label value contains invalid characters: '${ keyStr} ' = '${ valueStr} ' - only letters, numbers, spaces, and _ . : / = + - @ are allowed"
907
928
}
908
929
909
- result. put(sanitizedKey, sanitizedValue)
930
+ // Add valid entries to result
931
+ result[keyStr] = valueStr
932
+ }
933
+
934
+ // Handle violations based on strict mode (but only for constraint violations, not null filtering)
935
+ if (violations) {
936
+ final message = " AWS Batch tag validation failed:\n ${ violations.collect{ ' - ' + it }.join('\n')} "
937
+ if (strictMode) {
938
+ throw new ProcessUnrecoverableException (message)
939
+ } else {
940
+ log. warn " ${ message} \n Tags will be used as-is but may cause AWS Batch submission failures"
941
+ }
910
942
}
911
943
912
944
return result
913
945
}
914
946
915
947
/**
916
- * Sanitize a single label key or value for AWS Batch tags.
917
- * Replaces invalid characters with underscores and truncates if necessary.
918
- *
919
- * @param input The input string to sanitize
920
- * @param maxLength The maximum allowed length
921
- * @return The sanitized string
948
+ * Check if a string contains only characters allowed in AWS Batch tags.
949
+ * AWS Batch allows: letters, numbers, spaces, and: _ . : / = + - @
950
+ *
951
+ * @param input The string to validate
952
+ * @return true if the string contains only valid characters
922
953
*/
923
- protected String sanitizeAwsBatchLabel (String input , int maxLength ) {
924
- if (! input) return input
925
-
926
- // Replace invalid characters and clean up the string
927
- // AWS Batch allows: letters, numbers, spaces, and: _ . : / = + - @
928
- final sanitized = input
929
- .replaceAll(/ [^a-zA-Z0-9\s _.\:\/ =+\- @]/ , ' _' ) // Replace invalid chars with underscores
930
- .replaceAll(/ [_\s ]{2,}/ , ' _' ) // Replace multiple consecutive underscores/spaces
931
- .replaceAll(/ ^[_\s ]+|[_\s ]+$/ , ' ' ) // Remove leading/trailing underscores and spaces
932
-
933
- // Truncate if necessary and clean up any trailing underscores/spaces
934
- final result = sanitized. size() > maxLength
935
- ? sanitized. substring(0 , maxLength). replaceAll(/ [_\s ]+$/ , ' ' )
936
- : sanitized
937
-
938
- return result ?: null
954
+ protected boolean isValidAwsBatchTagString (String input , int maxLength = 128 ) {
955
+ if (! input) return false
956
+ if (input. length() > maxLength) return false
957
+ return input ==~ / ^[a-zA-Z0-9\s _.\:\/ =+\- @]*$/
939
958
}
940
959
941
960
/**
0 commit comments