Upgrade vanilla base 7.6.5 → 7.6.7 (diff-apply two-parent merge) - #1383
Open
milanmajchrak wants to merge 1450 commits into
Open
Upgrade vanilla base 7.6.5 → 7.6.7 (diff-apply two-parent merge)#1383milanmajchrak wants to merge 1450 commits into
milanmajchrak wants to merge 1450 commits into
Conversation
…of o-o operations [DS-3975] Includes toniprieto's suggested change in DSpace#2169 discussion and additional logging (e.g. how many bitstreams are missing). (cherry picked from commit fc1bd87)
Error found when running checker ITs in DSpace#11144. (cherry picked from commit c358e88)
[Port dspace-7_x] Fix updateMissingBitstreams to use single database operation instead of o-o operations [DS-3975] with logging
(cherry picked from commit 3a9f3b2)
[Port dspace-7_x] Add DataCite sandbox url to crosswalk
(cherry picked from commit 9ae59e7)
[Port dspace-7_x] SWORDv2 Added the bitstream encoding to the URL
[Port dspace-7_x] Make sure that bitstream downloads have a content-disposition header set
…_x/pdfbox-version-3.0.6
Bumps `log4j.version` from 2.25.2 to 2.25.3. Updates `org.apache.logging.log4j:log4j-api` from 2.25.2 to 2.25.3 Updates `org.apache.logging.log4j:log4j-core` from 2.25.2 to 2.25.3 Updates `org.apache.logging.log4j:log4j-1.2-api` from 2.25.2 to 2.25.3 --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-api dependency-version: 2.25.3 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.logging.log4j:log4j-core dependency-version: 2.25.3 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.logging.log4j:log4j-1.2-api dependency-version: 2.25.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
…_x/log4j.version-2.25.3
(cherry picked from commit 570fb9c)
(cherry picked from commit 1cb8827)
[Port dspace-7_x] DSpace 8.x bug fix link checker
Bumps the build-tools group with 4 updates: [org.sonatype.central:central-publishing-maven-plugin](https://github.com/sonatype/central-publishing-maven-plugin), [org.codehaus.mojo:xml-maven-plugin](https://github.com/mojohaus/xml-maven-plugin), [org.codehaus.mojo:license-maven-plugin](https://github.com/mojohaus/license-maven-plugin) and [org.codehaus.mojo:buildnumber-maven-plugin](https://github.com/mojohaus/buildnumber-maven-plugin). Updates `org.sonatype.central:central-publishing-maven-plugin` from 0.9.0 to 0.10.0 - [Commits](https://github.com/sonatype/central-publishing-maven-plugin/commits) Updates `org.codehaus.mojo:xml-maven-plugin` from 1.2.0 to 1.2.1 - [Release notes](https://github.com/mojohaus/xml-maven-plugin/releases) - [Commits](mojohaus/xml-maven-plugin@1.2.0...xml-maven-plugin-1.2.1) Updates `org.codehaus.mojo:license-maven-plugin` from 2.7.0 to 2.7.1 - [Release notes](https://github.com/mojohaus/license-maven-plugin/releases) - [Commits](mojohaus/license-maven-plugin@2.7.0...2.7.1) Updates `org.codehaus.mojo:buildnumber-maven-plugin` from 3.2.1 to 3.3.0 - [Release notes](https://github.com/mojohaus/buildnumber-maven-plugin/releases) - [Commits](mojohaus/buildnumber-maven-plugin@3.2.1...buildnumber-maven-plugin-3.3.0) --- updated-dependencies: - dependency-name: org.sonatype.central:central-publishing-maven-plugin dependency-version: 0.10.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: build-tools - dependency-name: org.codehaus.mojo:xml-maven-plugin dependency-version: 1.2.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: build-tools - dependency-name: org.codehaus.mojo:license-maven-plugin dependency-version: 2.7.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: build-tools - dependency-name: org.codehaus.mojo:buildnumber-maven-plugin dependency-version: 3.3.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: build-tools ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps the fasterxml group with 4 updates: [com.fasterxml:classmate](https://github.com/FasterXML/java-classmate), [com.fasterxml.jackson.core:jackson-annotations](https://github.com/FasterXML/jackson), [com.fasterxml.jackson.core:jackson-core](https://github.com/FasterXML/jackson-core) and [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson). Updates `com.fasterxml:classmate` from 1.7.1 to 1.7.3 - [Commits](FasterXML/java-classmate@classmate-1.7.1...classmate-1.7.3) Updates `com.fasterxml.jackson.core:jackson-annotations` from 2.20 to 2.21 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.core:jackson-core` from 2.20.1 to 2.21.0 - [Commits](FasterXML/jackson-core@jackson-core-2.20.1...jackson-core-2.21.0) Updates `com.fasterxml.jackson.core:jackson-databind` from 2.20.1 to 2.21.0 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.core:jackson-databind` from 2.20.1 to 2.21.0 - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml:classmate dependency-version: 1.7.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: fasterxml - dependency-name: com.fasterxml.jackson.core:jackson-annotations dependency-version: '2.21' dependency-type: direct:production update-type: version-update:semver-minor dependency-group: fasterxml - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-version: 2.21.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: fasterxml - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.21.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: fasterxml - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.21.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: fasterxml ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [org.apache.bcel:bcel](https://github.com/apache/commons-bcel) from 6.11.0 to 6.12.0. - [Changelog](https://github.com/apache/commons-bcel/blob/master/RELEASE-NOTES.txt) - [Commits](apache/commons-bcel@rel/commons-bcel-6.11.0...rel/commons-bcel-6.12.0) --- updated-dependencies: - dependency-name: org.apache.bcel:bcel dependency-version: 6.12.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [dnsjava:dnsjava](https://github.com/dnsjava/dnsjava) from 3.6.3 to 3.6.4. - [Release notes](https://github.com/dnsjava/dnsjava/releases) - [Changelog](https://github.com/dnsjava/dnsjava/blob/master/Changelog) - [Commits](dnsjava/dnsjava@v3.6.3...v3.6.4) --- updated-dependencies: - dependency-name: dnsjava:dnsjava dependency-version: 3.6.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.8 to 42.7.9. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](pgjdbc/pgjdbc@REL42.7.8...REL42.7.9) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-version: 42.7.9 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps the amazon-s3 group with 2 updates: software.amazon.awssdk:s3 and [software.amazon.awssdk.crt:aws-crt](https://github.com/awslabs/aws-crt-java). Updates `software.amazon.awssdk:s3` from 2.38.8 to 2.39.6 Updates `software.amazon.awssdk.crt:aws-crt` from 0.39.4 to 0.40.1 - [Release notes](https://github.com/awslabs/aws-crt-java/releases) - [Commits](awslabs/aws-crt-java@v0.39.4...v0.40.1) --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-version: 2.39.6 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: amazon-s3 - dependency-name: software.amazon.awssdk.crt:aws-crt dependency-version: 0.40.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: amazon-s3 ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps the apache-commons group with 4 updates in the / directory: [commons-codec:commons-codec](https://github.com/apache/commons-codec), org.apache.commons:commons-dbcp2, org.apache.commons:commons-pool2 and [org.apache.commons:commons-text](https://github.com/apache/commons-text). Updates `commons-codec:commons-codec` from 1.20.0 to 1.21.0 - [Changelog](https://github.com/apache/commons-codec/blob/master/RELEASE-NOTES.txt) - [Commits](apache/commons-codec@rel/commons-codec-1.20.0...rel/commons-codec-1.21.0) Updates `org.apache.commons:commons-dbcp2` from 2.13.0 to 2.14.0 Updates `org.apache.commons:commons-pool2` from 2.12.1 to 2.13.1 Updates `org.apache.commons:commons-text` from 1.14.0 to 1.15.0 - [Changelog](https://github.com/apache/commons-text/blob/master/RELEASE-NOTES.txt) - [Commits](apache/commons-text@rel/commons-text-1.14.0...rel/commons-text-1.15.0) --- updated-dependencies: - dependency-name: commons-codec:commons-codec dependency-version: 1.21.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: apache-commons - dependency-name: org.apache.commons:commons-dbcp2 dependency-version: 2.14.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: apache-commons - dependency-name: org.apache.commons:commons-pool2 dependency-version: 2.13.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: apache-commons - dependency-name: org.apache.commons:commons-text dependency-version: 1.15.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: apache-commons ... Signed-off-by: dependabot[bot] <support@github.com>
(cherry picked from commit cfff804)
[Port dspace-7_x] Move same-collection check to inheritDefaultPolicies move method (manual port)
…_x/org.apache.bcel-bcel-6.12.0 Bump org.apache.bcel:bcel from 6.11.0 to 6.12.0
…_x/dnsjava-dnsjava-3.6.4 Bump dnsjava:dnsjava from 3.6.3 to 3.6.4
…_x/fasterxml-8fce214327 Bump the fasterxml group with 4 updates
…_x/io.grpc-grpc-context-1.78.0 build(deps): bump io.grpc:grpc-context from 1.77.0 to 1.78.0
…_x/org.postgresql-postgresql-42.7.9 Bump org.postgresql:postgresql from 42.7.8 to 42.7.9
…_x/build-tools-57bb4f0b4d Bump the build-tools group with 4 updates
…_config-7_x [Port dspace-7_x] Velocity template engine configuration improvements
Removes some JDK >= 16 usage
(cherry picked from commit 6437472)
(cherry picked from commit 00e4979)
[Port dspace-7_x] Application hardening: filter requests for JSPs and other unwanted patterns
…ent-7_x [Port dspace-7_x] Curation I/O improvements
Applies the DSpace 7.6.5->7.6.7 delta onto the CLARIN fork dtq-dev as a two-parent merge with merge-base dspace-7.6.5. Resolves the 26 conflicting files per the section-4 recipes plus out-of-marker fixups: keep AWS SDK v1 S3 stack (aws-java-sdk-s3 @ 1.12.792 + s3mock), dedupe Swordv2IT depositItemWithEmbargo, bump json-smart pin to 2.6.0. Build-caught fixups (vanilla API changes / new tests vs CLARIN code): - AbstractCurationTask: re-added dereference(Context,String) helper that vanilla removed (inlined into perform()); CLARIN ItemMetadataQAChecker still calls it. - ItemServiceTest: updated findItemsWithEdit/countItemsWithEdit to the new String-query signature from PR DSpace#11953 (empty query preserves old behavior). - RequestItemRepositoryIT.testDeleteBitstreamRemovesRequestItem: reattach the bitstream/item to the session after the committed REST POST, so CLARIN updateItemFilesMetadata (run inside bitstream delete) sees an attached item. Validation: mvn install -P-assembly BUILD SUCCESS (all modules); VersioningTest 6/6, RequestItemRepositoryIT#testDeleteBitstreamRemovesRequestItem green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
milanmajchrak
force-pushed
the
upgrade/vanilla-7.6.7
branch
from
July 21, 2026 13:54
c257741 to
81dac88
Compare
…hib ITs - clarin-dspace.cfg: webui.content_disposition_inline allowlist (vanilla flipped blocklist->allowlist; text/plain, audio, tiff, csv would force-download). video/ogg is listed alongside audio/ogg because bitstream-formats.xml maps the .ogg extension to video/ogg, so audio/ogg alone would never match. - AuthenticationRestControllerIT: 2 new vanilla tests now use setAuthenticationMethodSequence() instead of unreliable setProperty() - test local.cfg: pin the vanilla allowlist for the test environment, otherwise the new CLARIN override reaches the ITs and breaks the upstream BitstreamRestControllerIT#checkContentDispositionOfFormats assertion on text/plain
Live rehearsal showed the previous wording ("must stay previewable inline") is
untrue for real file sizes: BitstreamRestController also enforces
webui.content_disposition_threshold, code default 8 MB, so most real audio/video
and large TIFF scans are sent as attachment despite being allowlisted.
Comment only - no value change. Raising the threshold widens the inline-render
surface and is left as a deliberate deployment decision.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
OAI (regression introduced by taking 7.6.7, breaks CLARIN's VLO/OLAC harvesting): vanilla 7.6.7 added ItemUtils.sanitize() and applies it to every metadata value before the XOAI serializer escapes it again, so any value containing & < > " ' reaches harvesters double-escaped. Measured live on cmdi and olac: REST: u767xssprobe <script>alert(1)</script> end cmdi: u767xssprobe &lt;script&gt;alert(1)&lt;/script&gt; end sanitize() now removes characters XML 1.0 forbids instead of escaping, which is what its own javadoc says it does. Upstream defect - should be reported upstream. content-disposition: the previous allowlist restored inline for only 14 of the 96 registered formats; 7.6.5 allowed 90 (every image/* was inline unconditionally). Added the omitted formats LINDAT actually serves - WebVTT subtitles, AIFF/AU/MPEG audio, JPEG2000/WebP/AVIF/BMP images, Quicktime. Also added the parameterised "text/plain; charset=utf-8": the allowlist is matched by exact string equality, so the registry's extension-less "License" format could never match a bare "text/plain" token and license bitstreams always downloaded. Still deliberately absent: HTML/XML/TEI/SVG/JS. Threshold left at the 8 MB default. Verified: dspace-oai compiles, checkstyle clean, sanitize() behaviour unit-checked (metachars pass through, illegal C0/noncharacters removed, tab/LF/CR and CJK kept). Test config pin keeps the vanilla value, so upstream BitstreamRestControllerIT is unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The previous commit replaced escapeXml10 with a regex to stop the double escaping, but escapeXml10 was an AggregateTranslator that ALSO ran UnicodeUnpairedSurrogateRemover, and the regex reproduced only the control-char part. Consequence: a lone surrogate in metadata (truncated 4-byte character, mojibake corpus) makes the StAX writer throw "Broken surrogate pair" inside XOAI.index(), and because that is caught per item the record is silently dropped from the OAI index. Measured before this fix: 2048 code units broke indexing, against 0 for vanilla 7.6.7. Verified over the whole BMP: 0 XML-1.0-illegal code units leak, 0 legal ones are removed, valid surrogate pairs survive, unpaired ones do not, and XML metacharacters still pass through unescaped. Known and intentional difference from escapeXml10: C0/DEL controls U+007F-U+009F are left as-is instead of being turned into &#NNN; entities. They are legal XML 1.0 characters (only XML 1.1 requires escaping them), so well-formedness is unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
7.6.7 rewrote S3BitStoreService from com.amazonaws (v1) to software.amazon.awssdk (v2 CRT client). The original plan rejected that and kept v1; the user reversed it: "if 7.6.7 is on AWS2, go to AWS2". v1 is past AWS end-of-support anyway. The fork owns three S3 classes vanilla does not know, so this was not a file takeover: - S3BitStoreService = vanilla 7.6.7 + exactly three CLARIN items (47 added lines): getFile(Bitstream), `protected` client so the subclasses can reuse it, and a configurable pathStyleAccessEnabled (vanilla hardcodes forcePathStyle(true) on an endpoint override; keeping the property preserves the fork's v1 behaviour and keeps bitstore.xml valid). getFile is byte-identical to the fork's own v9 implementation (5e930d1) so the branches do not diverge. - SyncS3BitStoreService - hand-ported, including the explicit multipart path. - S3DirectDownloadServiceImpl - presigning moved to S3Presigner, built from the same credentials/region/endpoint as the bitstore client. - S3BitStoreServiceIT - taken from 7.6.7 wholesale; the fork's copy was byte-identical to 7.6.5, so no CLARIN test was lost. LocalStack replaces s3mock, which only ever spoke v1. - ClarinS3BitStoreServiceIT - new. The CLARIN-only paths had no test at all. - bitstore.xml / assetstore.cfg - the merge had dropped vanilla's four new tuning keys (targetThroughputGbps, minPartSizeBytes, maxConcurrency, s3ChecksumAlgorithm). Two defects the new tests caught, neither visible by reading the code: 1. v1 returned part ETags unquoted, v2 returns them quoted. The multipart checksum comparison would have failed on every part, and since that path logs and swallows, completeMultipartUpload would never run - a silent upload failure. 2. SyncS3BitStoreService.put() never closed the FileOutputStream on the local assetstore copy. Pre-existing, not a port regression, but it leaks a handle per stored bitstream and made remove() silently fail to delete the local file. Evidence (local, this head): - mvn test-compile -DskipTests: 13/13 modules SUCCESS - S3BitStoreServiceIT Tests run: 15, Failures: 0, Errors: 0 - ClarinS3BitStoreServiceIT Tests run: 6, Failures: 0, Errors: 0 - S3DirectDownloadServiceTest Tests run: 8, Failures: 0, Errors: 0 - checkstyle 0 violations; `git grep com.amazonaws` finds nothing s3Store is lazy-init and nothing else instantiates it, so springWiringBindsStoreProperties loads the bean from bitstore.xml on purpose - it is the only check that the blank maxConcurrency binds to a null Integer and that s3ChecksumAlgorithm binds to the enum. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
**Silent data loss on multipart upload.** `uploadPart` was handed a `BoundedInputStream`
over a `FileInputStream`, which cannot be reset, so the SDK refused to retry a part after
any transient error ("Request cannot be retried, because the request stream could not be
reset"). The v1 SDK passed the file plus an offset and retried freely. The failure then
landed in a catch that logged and swallowed, `completeMultipartUpload` never ran, and
`put()` carried on setting size and checksum - DSpace recorded a bitstream that S3 does
not hold, with no error anywhere.
Now uses the public `AsyncRequestBody.fromFile(FileRequestBodyConfiguration)` with
`position`/`numBytesToRead`, which is file-backed and therefore retryable; this also
removes the hand-rolled `openPart` helper and its executor. A failed upload now aborts the
multipart upload (parts were previously leaked and billed) and throws instead of returning
normally.
**The multipart loop was never executed more than once.** 50 MB part size against a 23-byte
fixture meant one iteration with offset 0, so the offset arithmetic and last-part handling
this port rewrote had no coverage at all. `uploadPartSizeBytes` is now settable and
`syncStoreUploadsInMultipleParts` uploads 5 MB + 4 KB across a real part boundary, verifying
the object byte for byte.
**A tripwire in `amazonClientBuilderBy` left all 21 S3 tests green.** Every test injects a
ready-made client, so `FunctionalUtils.getDefaultOrBuild` never called the supplier and
`endpointOverride`, `forcePathStyle`, `maxConcurrency` and the part sizes never ran - the
fork's headline delta, configurable `pathStyleAccessEnabled`, was verified only at its
getter. `clientBuilderAppliesEndpointAndPathStyle` builds a client through that method and
uses it against LocalStack. Verified it detects breakage: removing `endpointOverride` turns
it red, restoring it turns it green.
**Content-Disposition had two implementations and the newer one was wrong.** It escaped `"`
but not `\`, so a bitstream named `evil\` terminated the quoted string and swallowed
`filename*`; and it used `URLEncoder` directly, so a space arrived as `+`, which RFC 8187
reads literally - re-introducing the bug vanilla had just fixed. Extracted the correct
implementation to `org.dspace.util.ContentDispositionUtils`, now used by both call sites.
**Enabling direct downloads silently disabled inline preview.** The redirect hardcoded
`attachment`, discarding the disposition the allowlist and the 8 MB threshold had just
computed. `generatePresignedUrl` takes the caller's disposition; `BitstreamRestController`
passes the exact header the non-redirect path would have sent.
**Presigner region could diverge from the client's.** It hardcoded `us-east-1` while the
client leaves the region to the default provider chain when no credentials are configured,
so presigned URLs would be signed for the wrong region on an IAM role outside us-east-1. It
now mirrors `init()` branch for branch.
**A 403 was reported as "bucket absent".** `doesBucketExist` treated everything except
`NoSuchBucketException` as absent, so `init()` would try to create a bucket that already
exists; a least-privilege policy denies that and the assetstore comes up dead. Only 404 and
`NoSuchBucketException` now answer false. `doesObjectExist` likewise stops reporting a 403
or a timeout as "object does not exist" with the cause hidden at DEBUG.
**`s3ChecksumAlgorithm` was dead configuration.** `bitstore.xml` wires
`SyncS3BitStoreService`, which overrides `put()`, so the parent's `putObject` - the only
consumer - never ran. `uploadFluently` now applies it. Also `${assetstore.s3.endpoint:}` is
self-defaulting, matching vanilla.
Tests: S3BitStoreServiceIT 15, ClarinS3BitStoreServiceIT 8, S3DirectDownloadServiceTest 11,
ContentDispositionUtilsTest 9 - all 0 failures, checkstyle 0 violations. Maven does not
recompile edited sources reliably here, so every run used
`-Dmaven.compiler.useIncrementalCompilation=false`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`ItemUtils.sanitize()` decides what VLO and OLAC receive, was changed twice in this PR, and had no test at all - a reviewer called it the highest-risk file in the upgrade for exactly that reason. `OAIPMHBundleExposureIT` already drove `ItemUtils.retrieveMetadata()`, so the harness existed; this uses the same serialisation path as `DSpaceXOAIItemCacheService.put()` and re-parses the result, because writing alone proves nothing - `U+FFFE` serialises happily and only fails on the harvester's parser. Four cases: metacharacters round-trip exactly once (the double-escaping 7.6.6 introduced); control characters and unpaired surrogates are removed rather than throwing inside `XOAI.index()`, which catches per item and would silently drop the record; supplementary characters and `U+1FFFE` survive while `U+FFFE` does not; and the output always re-parses. Verified non-vacuous: making `sanitize()` return its input unchanged turns three of the four red, with `WritingXmlException` and `SAXParseException` - the exact failure modes the fix exists to prevent. Two things the test itself established, both recorded in comments so nobody re-derives them: `U+0000` never reaches the sanitiser because PostgreSQL cannot store a NUL in a text column, and DSpace replaces C0 controls with a space before persisting, so the spacing around a removed control character is the persistence layer's doing and not something this test can assert on. Also fixes the import order `ContentDispositionUtils` was inserted at in `BitstreamByHandleRestController` (checkstyle). Tests: OAIPMHSanitizeIT 4, OAIPMHBundleExposureIT 3, 0 failures, checkstyle 0 violations. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Upgrades the fork's vanilla base from 7.6.5 to 7.6.7 (7.6.6 + 7.6.7, mostly security/bugfix maintenance).
Problem
The fork sat on vanilla 7.6.5 and was missing two maintenance releases, including the CVE-2026-49830/49831 cluster and the content-disposition XSS hardening.
Root cause of the awkward merge
git merge-base dtq-dev vanillaisdspace-7.6.1, not 7.6.5 — the fork carries 7.6.2–7.6.5 textually (via CLARIN ports), not as ancestry. A plaingit merge dspace-7.6.7re-litigates the whole 7.6.1→7.6.7 range: 111 conflicted files.Change set
Applied only the true 7.6.5→7.6.7 delta (
git merge-tree --merge-base=dspace-7.6.5) = 26 conflicts, committed viagit commit-treeas a real two-parent merge somerge-baseis permanently repaired — 7.6.8 will be an ordinary small merge.81dac88c0700501a2db0, ^2 =dspace-7.6.7), 26 conflicts resolved per recipe + 6 out-of-marker fixups51f4b9e012e4978e2b95c6a1101410b28457142a1bfc45b88875848b2639doesBucketExist403,ContentDispositionUtils, presign region + disposition)4b5390f9d4OAIPMHSanitizeIT— the OAI sanitizer's first test, mutation-verifiedTest evidence
CI green on the head being merged (
4b5390f9d4) — 9 success + 1 skipped (dspace-redeploy, skipped on PRs by design), 0 failures. Maven prints no reactor-wide total, so these are the per-module summaries (run30882484223):-DskipIntegrationTests=false— 540 (dspace-api) + 1 (Additions) + 3362 (server-webapp) + 1 (Local Customizations) = 3904 tests, 0 failures, 0 errors, 60 skipped. dspace-api went 532 -> 540: the eight newClarinS3BitStoreServiceITcases, confirmed by name in the CI log alongsideS3BitStoreServiceITat 15; server-webapp gained the 4OAIPMHSanitizeITcases-DskipUnitTests=false— 78 (services) + 1328 (dspace-api) + 1 (deprecated REST) + 8 (dspace-oai) + 145 (server-webapp) = 1560 tests, 0 failures, 0 errors, 12 skippedrerunFailingTestsCount=2; all docker-builds pass; checkstyle 0 violations - from a localmvn verify, NOT from this CI run: the Build workflow passes-Dcheckstyle.skip=trueNote for future reviews: PR CI tests the merge of this head with the moving base, so the server-webapp figure moved 3357→3358 when
dtq-dev-767-baseadvanced — not nondeterminism.Live rehearsal on a local stack built from this branch:
Ignored; plaindspace database migrate(what the compose entrypoint runs) does not apply them;dspace database migrate ignoreddoes.entity_type_label_upper_idxcreated.V7.6_2025.10.29blast radius measured: of 3requestitemrows it deleted exactly 1 — the one bound tobitstream.deleted IS TRUE. Rows withNULL bitstream_idand rows on live bitstreams survived.text/plain,text/csv,image/tiff,application/pdf→inline;text/html,text/xml/TEI →attachment.*_year, HtmlEncoder highlight) and fork (ASCIIFolding,items_owning_community,dspaceAutoComplete) changes;index-discovery -bcompletes and search returns results.Feature parity vs
dtq-dev: the merge touched none of the 198 CLARIN-named files; 7 files disappeared: 6 are vanilla deletes that were byte-identical to 7.6.5, the 7th isCmdiDownloadLinkIT.java, a CLARIN-only IT that arrived on the base branch in #1384 after this branch was cut - the merge restores it in the fork. Everyclass="org.dspace..."in Spring XML resolves to a source file — re-measured at HEAD: 588 distinct candidates, 0 unresolved. (Six were flagged by a naive scan and all six are artefacts: threeConstants.*static fields, one nested enumRole.Scope, one bean name rather than a class, andCiniiMetadataContributor, which sits inside an XML comment and is equally absent from vanilla 7.6.7.) Flyway migration scripts 149→152 (the 183→186 figure counted everything understorage/rdbms, Java sources included), 0 lost.Scope beyond the 26 conflicts (each load-bearing, none incidental)
AbstractCurationTask.java— re-addeddereference(Context,String)that 7.6.7 deleted; CLARIN-onlyItemMetadataQAChecker:409calls it. Compile fix.ItemServiceTest.java— 5 call sites updated to vanilla's newString qparameter.RequestItemRepositoryIT.java—context.reloadEntitybeforebitstreamService.delete; CLARINupdateItemFilesMetadataneeds an attached item. Test-scoped, not a production change.dspace/config/clarin-dspace.cfg— CLARIN inline allowlist. 7.6.7 flipped this key from blocklist to allowlist, so without ittext/plaincorpora, audio, TIFF scans and CSV silently became force-download. HTML/XML/TEI/SVG/JS deliberately excluded.dspace-api/src/test/data/dspaceFolder/config/local.cfg— pins the vanilla value for tests.testEnvironment.zipshipsclarin-dspace.cfgintodspace.dir, so item 4 alone turnedBitstreamRestControllerIT.checkContentDispositionOfFormatsred. Keeps the upstream test file byte-identical to vanilla.AuthenticationRestControllerIT.java— the 2 new vanilla Shib tests were the only 2 of 22 sites still using plainsetProperty()for the auth plugin sequence, which this file's own javadoc documents as silently discarded under CLARIN config auto-reload. Switched to the fork'ssetAuthenticationMethodSequencehelper.dspace-oai/.../ItemUtils.java— see below.The one vanilla defect we had to work around
7.6.6 added
ItemUtils.sanitize()=StringEscapeUtils.escapeXml10(value)and applies it to every metadata value before the XOAI serializer escapes it again. Everything containing& < > " 'reaches harvesters double-escaped. Measured live:That corrupts
cmdiandolac— CLARIN/LINDAT's primary machine interface (VLO, OLAC).sanitize()now removes characters XML 1.0 forbids instead of escaping them, which is what its own javadoc says it does. Escaping is not lost:Element$Field.write()hands every value toXMLStreamWriter.writeCharacters(), which escapes on its own — it was simply being done twice.b28457142acompletes that fix.escapeXml10was anAggregateTranslatorthat also ranUnicodeUnpairedSurrogateRemover, and the first version reproduced only the control-character part. A lone surrogate (truncated 4-byte character, mojibake corpus) then makes the StAX writer throwBroken surrogate pairinsideXOAI.index(), and since that is caught per item the record is silently dropped from the OAI index — 2048 code units affected, against 0 for vanilla. Verified across the whole BMP: 0 illegal code units leak, 0 legal ones are removed, valid surrogate pairs survive, unpaired ones do not, metacharacters still pass unescaped. Deliberate remaining difference: C0/DELU+007F–U+009Fare left literal instead of becoming&#NNN;; they are legal XML 1.0 characters, so well-formedness is unaffected.This is an upstream defect and should be reported to DSpace/DSpace.
Risk
dspace database migrate ignoredis irreversible andV7.6_2025.10.29deletes rows. Snapshotrequestitemfirst (blast radius above).dspace-7_x.webui.content_disposition_threshold(code default 8 MB) still sends larger files asattachment. Left unchanged deliberately; raising it widens the inline-render surface.audio/flac,audio/oggandaudio/wavare inert until those formats are added to the registry (backlog).Rollback
Revert the 7 CLARIN commits above plus the merge
81dac88c07, or simply reset the branch to00501a2db0. Nothing is deployed by merging. Already-runmigrate ignoredis not revertible — restore from the pre-migration snapshot.Non-goals / still open
Playwright suite, CLARIN license-gated download / preview+tgz / Shibboleth / request-a-copy happy path, staged rollout via sha tag, v9-ledger closure, customer branches.
ui.baseUrlmust be set in the deployment overlay (see the FE PR).Sign-off status: D1, D5 and D7 were answered by the maintainer and are implemented. D2, D3, D4 and D6
were queried, explained in
UPGRADE_767_QUESTIONS.md, and still have no decision — the branch ships thedocumented default for each. Merging accepts those defaults. What the audit deliberately did not fix,
and why, is listed in
UPGRADE_767_AUDIT.md§2.🤖 Generated with Claude Code
No compose path applies the two new migrations. Verified in
DatabaseUtils.java:migrate ignoredpassesoutOfOrder=true, butmigrate forcepassesoutOfOrder=falseand plainmigratedefaults to false. This repo'sdocker-compose.yml:67runs plainmigrate; the FE composes runmigrate force. So both new migrations stayIgnoredforever — theentity_type_label_upper_idxindex is never created and the requestitem cleanup never runs, with no error and no log line.dspace database migrate ignoredtherefore has to be run manually per instance, after snapshottingrequestitem. That is exactly what the G4 runbook says; this note records why it cannot be skipped. Switching compose tomigrate ignoredwould make the destructive migration run automatically on every stack start — deliberately not done here.Pair with the FE PR's
ui.baseUrlprerequisite (see dataquest-dev/dspace-angular#1398).AWS SDK v2 port (
1bfc45b888) — added 2026-08-037.6.7 rewrote
S3BitStoreServicefromcom.amazonaws(v1) tosoftware.amazon.awssdk(v2 CRT client). This PRoriginally rejected that and kept v1; the user reversed the decision — v1 is past AWS end-of-support anyway.
The fork owns three S3 classes vanilla does not know, so this was not a file takeover:
S3BitStoreService+58/-8vsdspace-7.6.7at HEAD; was+47/-5before the audit fixes):getFile(Bitstream), aprotectedclient so the subclasses can reuse it, and a configurablepathStyleAccessEnabled. Vanilla hardcodesforcePathStyle(true)on an endpoint override; keeping the property preserves the fork's v1 behaviour and keepsbitstore.xmlvalid.SyncS3BitStoreService(339 lines, 199 non-comment)S3DirectDownloadServiceImpl(204 lines, 142 non-comment)S3Presigner, built from the same credentials/region/endpoint as the bitstore clientS3BitStoreServiceITs3mock, which only ever spoke v1.ClarinS3BitStoreServiceITbitstore.xml,assetstore.cfgtargetThroughputGbps,minPartSizeBytes,maxConcurrency,s3ChecksumAlgorithm)getFileis not a new invention: it is byte-identical to the fork's own v9 implementation (5e930d1f2a), so the7.x and v9 branches do not diverge on it.
Two defects the new tests caught — neither visible by reading the code
would have failed on every part, and because that path logs and swallows,
completeMultipartUploadwouldnever run — a silently failed upload with a bitstream row pointing at nothing.
FileOutputStream.SyncS3BitStoreService.put()never closed the output stream on the localassetstore copy. Pre-existing, not a port regression, but it leaks a handle per stored bitstream and made
remove()silently fail to delete the local file.Evidence
mvn test-compile -DskipTests— Reactor Summary 13/13 modules SUCCESSS3BitStoreServiceIT(vanilla, LocalStack) —Tests run: 15, Failures: 0, Errors: 0ClarinS3BitStoreServiceIT(new) —Tests run: 8, Failures: 0, Errors: 0S3DirectDownloadServiceTest—Tests run: 11, Failures: 0, Errors: 0ContentDispositionUtilsTest(new) —Tests run: 9, Failures: 0, Errors: 0OAIPMHSanitizeIT(new) —Tests run: 4, Failures: 0, Errors: 0git grep com.amazonawsfinds nothing anywhere in the trees3Storeislazy-initandassetstore.index.primarydefaults to the local store, so nothing otherwiseinstantiates the bean —
springWiringBindsStorePropertiespulls it out of the service manager on purpose. It is theonly check that the blank
maxConcurrencybinds to a nullIntegerand thats3ChecksumAlgorithmbinds to the enum.Not covered by tests
No test talks to a real non-AWS endpoint, so the CESNET/MinIO path (
endpoint+pathStyleAccessEnabled) and thepresigned-URL path are verified against LocalStack and mocks only. Worth one manual download check on a dev instance
with S3 enabled before this reaches production.
Independent audit round (2026-08-04) — 10 reviewers, and what they found
Ten independent reviewers audited this PR, each on a separate area, all told to disprove rather than
confirm. They found real defects; the fixes are the two commits above
1bfc45b888(75848b2639,4b5390f9d4) plusff96c2cadain the FE PR.Fixed here
uploadPartgot a non-resettable stream, so any transient S3 error became permanent; the failure was then logged and swallowed andput()still recorded the bitstream — a DB row pointing at an object S3 does not have. Now usesAsyncRequestBody.fromFile(FileRequestBodyConfiguration), aborts the upload, and throws.syncStoreUploadsInMultiplePartsnow crosses a real part boundary and verifies the object byte for byte.amazonClientBuilderByleft all 21 S3 tests greenendpointOverride,forcePathStyle,maxConcurrencyand the part sizes never executed. The fork's headline delta — configurablepathStyleAccessEnabled— was verified only at its getter. Now covered by a test proven to go red whenendpointOverrideis removed."but not\, and usedURLEncoderso a space arrived as+. Extracted toContentDispositionUtils, used by both call sites.attachment, discarding the disposition the allowlist had just computed.us-east-1; now mirrorsinit()branch for branch.init()would try to create an existing bucket; a least-privilege policy denies that and the assetstore comes up dead.s3ChecksumAlgorithmwas dead configbitstore.xmlwiresSyncS3BitStoreService, which overridesput(), so the only consumer never ran.ItemUtils.sanitize()had no testOAIPMHSanitizeIT, verified non-vacuous: disabling the sanitiser turns 3 of 4 red withWritingXmlExceptionandSAXParseException.Corrections to earlier claims in this description
ItemUtils.sanitize()arrived in 7.6.6, not 7.6.7.CmdiDownloadLinkIT), not a vanilla delete. Risk is nil — the base branch restores it — but the original sentence implied no CLARIN file was affected.storage/rdbms; the migration-script count is 149→152.db.entities.ymlin both repos runsmigrate ignored. The conclusion about the deploy path stands —deploy.ymluses onlydocker-compose.ymland-rest.yml.-Dcheckstyle.skip=true; that claim comes from local runs.Known and deliberately not fixed
dspace-api/src/test/data/dspaceFolder/config/local.cfgpins the vanilla list and beatsclarin-dspace.cfg, which is what keeps the upstream IT green. Fixing it means giving the CLARIN list its own IT.dtq-dev, 68 of 97 registry formats flip inline → attachment (office, OpenDocument, archives, TeX). That is the allowlist semantics change working as intended, but users will notice.dspace checker -a <handle>was renamed to-iupstream, andchecker-emailer's long options were recased. Any cron using the old spellings breaks silently after deploy.get()no longer reads in 5 MB ranges (vanilla droppedS3LazyInputStream); a single stream is held open for the whole object, which exposes proxy idle timeouts on multi-GB corpora that chunking used to hide.deleteOnExit, which only fires on a clean JVM shutdown. Pre-existing, but it scales with corpus size.@IfProfileValue(name="s3.download.direct.enabled", value="true")and nothing sets that property.