Skip to content

Commit ec812b3

Browse files
committed
Fix thumbnail and attachment multipart uploads
1 parent 1753e42 commit ec812b3

9 files changed

Lines changed: 151 additions & 30 deletions

File tree

AssetAdministrationShellRepositoryServiceSpecification/V3.2_SSP-001.yaml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -380,11 +380,14 @@ paths:
380380
schema:
381381
type: object
382382
properties:
383-
fileName:
384-
type: string
385383
file:
386384
type: string
387385
format: binary
386+
description: >-
387+
Binary content. A source filename, if supplied, is conveyed in the
388+
`filename` parameter of this part's `Content-Disposition` header.
389+
required:
390+
- file
388391
encoding:
389392
file:
390393
contentType: application/octet-stream
@@ -1506,11 +1509,14 @@ paths:
15061509
schema:
15071510
type: object
15081511
properties:
1509-
fileName:
1510-
type: string
15111512
file:
15121513
type: string
15131514
format: binary
1515+
description: >-
1516+
Binary content. A source filename, if supplied, is conveyed in the
1517+
`filename` parameter of this part's `Content-Disposition` header.
1518+
required:
1519+
- file
15141520
encoding:
15151521
file:
15161522
contentType: application/octet-stream

AssetAdministrationShellRepositoryServiceSpecification/V3.2_SSP-005.yaml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,14 @@ paths:
213213
schema:
214214
type: object
215215
properties:
216-
fileName:
217-
type: string
218216
file:
219217
type: string
220218
format: binary
219+
description: >-
220+
Binary content. A source filename, if supplied, is conveyed in the
221+
`filename` parameter of this part's `Content-Disposition` header.
222+
required:
223+
- file
221224
encoding:
222225
file:
223226
contentType: application/octet-stream
@@ -507,11 +510,14 @@ paths:
507510
schema:
508511
type: object
509512
properties:
510-
fileName:
511-
type: string
512513
file:
513514
type: string
514515
format: binary
516+
description: >-
517+
Binary content. A source filename, if supplied, is conveyed in the
518+
`filename` parameter of this part's `Content-Disposition` header.
519+
required:
520+
- file
515521
encoding:
516522
file:
517523
contentType: application/octet-stream

AssetAdministrationShellServiceSpecification/V3.2_SSP-001.yaml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,14 @@ paths:
186186
schema:
187187
type: object
188188
properties:
189-
fileName:
190-
type: string
191189
file:
192190
type: string
193191
format: binary
192+
description: >-
193+
Binary content. A source filename, if supplied, is conveyed in the
194+
`filename` parameter of this part's `Content-Disposition` header.
195+
required:
196+
- file
194197
encoding:
195198
file:
196199
contentType: application/octet-stream
@@ -1289,11 +1292,14 @@ paths:
12891292
schema:
12901293
type: object
12911294
properties:
1292-
fileName:
1293-
type: string
12941295
file:
12951296
type: string
12961297
format: binary
1298+
description: >-
1299+
Binary content. A source filename, if supplied, is conveyed in the
1300+
`filename` parameter of this part's `Content-Disposition` header.
1301+
required:
1302+
- file
12971303
encoding:
12981304
file:
12991305
contentType: application/octet-stream

Entire-API-Collection/V3.2.yaml

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,14 @@ paths:
191191
schema:
192192
type: object
193193
properties:
194-
fileName:
195-
type: string
196194
file:
197195
type: string
198196
format: binary
197+
description: >-
198+
Binary content. A source filename, if supplied, is conveyed in the
199+
`filename` parameter of this part's `Content-Disposition` header.
200+
required:
201+
- file
199202
encoding:
200203
file:
201204
contentType: application/octet-stream
@@ -1308,11 +1311,14 @@ paths:
13081311
schema:
13091312
type: object
13101313
properties:
1311-
fileName:
1312-
type: string
13131314
file:
13141315
type: string
13151316
format: binary
1317+
description: >-
1318+
Binary content. A source filename, if supplied, is conveyed in the
1319+
`filename` parameter of this part's `Content-Disposition` header.
1320+
required:
1321+
- file
13161322
encoding:
13171323
file:
13181324
contentType: application/octet-stream
@@ -2535,11 +2541,14 @@ paths:
25352541
schema:
25362542
type: object
25372543
properties:
2538-
fileName:
2539-
type: string
25402544
file:
25412545
type: string
25422546
format: binary
2547+
description: >-
2548+
Binary content. A source filename, if supplied, is conveyed in the
2549+
`filename` parameter of this part's `Content-Disposition` header.
2550+
required:
2551+
- file
25432552
encoding:
25442553
file:
25452554
contentType: application/octet-stream
@@ -3265,11 +3274,14 @@ paths:
32653274
schema:
32663275
type: object
32673276
properties:
3268-
fileName:
3269-
type: string
32703277
file:
32713278
type: string
32723279
format: binary
3280+
description: >-
3281+
Binary content. A source filename, if supplied, is conveyed in the
3282+
`filename` parameter of this part's `Content-Disposition` header.
3283+
required:
3284+
- file
32733285
encoding:
32743286
file:
32753287
contentType: application/octet-stream
@@ -4404,11 +4416,14 @@ paths:
44044416
schema:
44054417
type: object
44064418
properties:
4407-
fileName:
4408-
type: string
44094419
file:
44104420
type: string
44114421
format: binary
4422+
description: >-
4423+
Binary content. A source filename, if supplied, is conveyed in the
4424+
`filename` parameter of this part's `Content-Disposition` header.
4425+
required:
4426+
- file
44124427
encoding:
44134428
file:
44144429
contentType: application/octet-stream
@@ -6051,11 +6066,14 @@ paths:
60516066
schema:
60526067
type: object
60536068
properties:
6054-
fileName:
6055-
type: string
60566069
file:
60576070
type: string
60586071
format: binary
6072+
description: >-
6073+
Binary content. A source filename, if supplied, is conveyed in the
6074+
`filename` parameter of this part's `Content-Disposition` header.
6075+
required:
6076+
- file
60596077
encoding:
60606078
file:
60616079
contentType: application/octet-stream

SubmodelRepositoryServiceSpecification/V3.2_SSP-001.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,11 +1274,14 @@ paths:
12741274
schema:
12751275
type: object
12761276
properties:
1277-
fileName:
1278-
type: string
12791277
file:
12801278
type: string
12811279
format: binary
1280+
description: >-
1281+
Binary content. A source filename, if supplied, is conveyed in the
1282+
`filename` parameter of this part's `Content-Disposition` header.
1283+
required:
1284+
- file
12821285
encoding:
12831286
file:
12841287
contentType: application/octet-stream

SubmodelRepositoryServiceSpecification/V3.2_SSP-003.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -939,11 +939,14 @@ paths:
939939
schema:
940940
type: object
941941
properties:
942-
fileName:
943-
type: string
944942
file:
945943
type: string
946944
format: binary
945+
description: >-
946+
Binary content. A source filename, if supplied, is conveyed in the
947+
`filename` parameter of this part's `Content-Disposition` header.
948+
required:
949+
- file
947950
encoding:
948951
file:
949952
contentType: application/octet-stream

SubmodelServiceSpecification/V3.2_SSP-001.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -951,11 +951,14 @@ paths:
951951
schema:
952952
type: object
953953
properties:
954-
fileName:
955-
type: string
956954
file:
957955
type: string
958956
format: binary
957+
description: >-
958+
Binary content. A source filename, if supplied, is conveyed in the
959+
`filename` parameter of this part's `Content-Disposition` header.
960+
required:
961+
- file
959962
encoding:
960963
file:
961964
contentType: application/octet-stream

documentation/IDTA-01002-3/modules/ROOT/pages/changelog.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ This section also includes an overview of how to expose the DPP interactions thr
2828

2929
Minor Changes:
3030

31+
* fix: Required the binary `file` part for thumbnail and attachment uploads and removed the redundant `fileName` multipart field; optional source filenames are conveyed by the standard `filename` parameter of each file part.
3132
* fix: Required the binary `file` part for AASX package uploads and removed the redundant `fileName` multipart field; an optional source filename is conveyed by the standard `filename` parameter of the file part.
3233
* fix: Corrected `USEATTRIBUTES` in the access-rule JSON Schema to accept a list, so one ACL can reference multiple named attribute groups as defined by the BNF.
3334
* fix: Marked the Query request body as required in all repository and registry query profiles, matching the mandatory query input in the interface definitions.

tools/validate_spec_artifacts.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
]
3939
OPENAPI_SCHEMA = ROOT / "Part2-API-Schemas/openapi.yaml"
4040
COMBINED_OPENAPI = ROOT / "Entire-API-Collection/V3.2.yaml"
41+
MULTIPART_OPENAPI_FILES = (
42+
COMBINED_OPENAPI,
43+
*sorted(ROOT.glob("*ServiceSpecification/V3.2*.yaml")),
44+
)
4145
OPERATION_RIGHT_MAPPING = ROOT_MODULE / "pages/annex/operation-to-right-mapping.adoc"
4246
QUERY_EXAMPLES = [
4347
ROOT_MODULE / "pages/http-rest-api/test/query/test1.json",
@@ -414,6 +418,76 @@ def parse_combined_openapi_operations(
414418
return operations
415419

416420

421+
def validate_multipart_file_uploads(validation: Validation) -> None:
422+
uploads_found = 0
423+
424+
for openapi_path in MULTIPART_OPENAPI_FILES:
425+
try:
426+
document = yaml.safe_load(openapi_path.read_text(encoding="utf-8-sig"))
427+
except Exception as exc: # noqa: BLE001 - keep parser detail in output.
428+
validation.fail(openapi_path, f"invalid YAML: {exc}")
429+
continue
430+
431+
paths = document.get("paths") if isinstance(document, dict) else None
432+
if not isinstance(paths, dict):
433+
validation.fail(openapi_path, "missing or invalid paths object")
434+
continue
435+
436+
for path, path_item in paths.items():
437+
if not isinstance(path_item, dict):
438+
continue
439+
for method in OPENAPI_HTTP_METHODS:
440+
operation = path_item.get(method)
441+
if not isinstance(operation, dict):
442+
continue
443+
444+
request_body = operation.get("requestBody")
445+
if not isinstance(request_body, dict):
446+
continue
447+
content = request_body.get("content")
448+
if not isinstance(content, dict):
449+
continue
450+
multipart = content.get("multipart/form-data")
451+
if not isinstance(multipart, dict):
452+
continue
453+
schema = multipart.get("schema")
454+
if not isinstance(schema, dict):
455+
continue
456+
properties = schema.get("properties")
457+
if not isinstance(properties, dict) or "file" not in properties:
458+
continue
459+
460+
uploads_found += 1
461+
location = f"{method.upper()} {path}"
462+
if "fileName" in properties:
463+
validation.fail(openapi_path, f"{location} declares a separate fileName multipart part")
464+
465+
required = schema.get("required")
466+
if not isinstance(required, list) or "file" not in required:
467+
validation.fail(openapi_path, f"{location} does not require the binary file part")
468+
469+
file_schema = properties["file"]
470+
if not isinstance(file_schema, dict):
471+
validation.fail(openapi_path, f"{location} has an invalid file schema")
472+
continue
473+
if file_schema.get("type") != "string" or file_schema.get("format") != "binary":
474+
validation.fail(openapi_path, f"{location} file part is not a binary string")
475+
476+
description = file_schema.get("description")
477+
if (
478+
not isinstance(description, str)
479+
or "filename" not in description
480+
or "Content-Disposition" not in description
481+
):
482+
validation.fail(
483+
openapi_path,
484+
f"{location} does not document the standard multipart filename parameter",
485+
)
486+
487+
if uploads_found == 0:
488+
validation.fail(ROOT, "no multipart file uploads found")
489+
490+
417491
def validate_operation_right_mapping(validation: Validation) -> None:
418492
operations = parse_combined_openapi_operations(validation)
419493
rows: dict[str, tuple[str, str, str, str, int]] = {}
@@ -479,6 +553,7 @@ def main() -> int:
479553
validation = Validation()
480554
validate_json_schema(validation)
481555
validate_bnf_grammar_files(validation)
556+
validate_multipart_file_uploads(validation)
482557
validate_operation_right_mapping(validation)
483558
validation.assert_ok()
484559
print("OK: spec artifact validation completed")

0 commit comments

Comments
 (0)