Fix: BoxLang signature failure — use isNull() instead of structKeyExists(arguments,...) for optional date overrides - #47
Conversation
…nal date overrides structKeyExists(arguments, "x") is not a safe way to test whether an optional, no-default argument was passed: on engines with full null support (BoxLang defaults to this, unlike Lucee's default partial null support), an unpassed argument still exists as a key holding null, so structKeyExists() returns true. In generateSignatureData() (Sv4Util.cfc and Sv2Util.cfc), both callers in AmazonS3.cfc omit amzDate and dateStamp entirely, but on BoxLang structKeyExists(arguments, "amzDate") is still true, so the code reads arguments.dateStamp (a real null) and passes it into buildCredentialScope()'s required dateStamp parameter, which BoxLang correctly rejects as missing: Error: Required argument dateStamp is missing for function buildCredentialScope This breaks every signed S3 request (PUT/GET/DELETE/etc.) on the boxlang@1 engine. Check each optional argument independently with isNull() instead, which is null-support-safe on every engine and degrades correctly when only one of the two is actually passed. Applied the same fix to MiniLogBox.cfc's debug/error/warn(), which had the identical structKeyExists(arguments, "data") pattern for its optional data parameter. Note: this repo's own CI matrix (.github/workflows/tests.yml) tests boxlang-cfml@1 but not the native boxlang@1 engine, which is why this went uncaught.
…ng support, refresh docs and CI matrix - copyObject()/renameObject(): remove manually-set Content-Length header that duplicated CFHTTP's own header on bodyless requests, causing SignatureDoesNotMatch on Adobe CF and BoxLang - Sv4Util.cfc/Sv2Util.cfc: fix dateFormat() mask from "yyyymmdd" (minutes) to "yyyyMMdd" (month) for cross-engine correctness - Fix server-boxlang-cfml@1.json leftover aliases copied from another module - Add native BoxLang (boxlang@1) server config and CI matrix entry - CI matrix: drop lucee@5, adobe@2018, adobe@2021; add lucee@6, adobe@2023, adobe@2025; bump ColdBox to ^8 - box.json: swap commandbox-dotenv/commandbox-cfconfig devDependencies for commandbox-boxlang; update shortDescription - test-harness/box.json: bump coldbox dependency to ^8 - Rewrite readme.md (BoxLang-first, expanded usage/config/testing docs) and update changelog.md - Add AGENTS.md with engine-portability guidance for coding agents - Run cfformat --overwrite across the project Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
…b.com/coldbox-modules/s3sdk into fix/boxlang-signature-date-null-check
Breaking changes in this branch (dropped Adobe 2018/2021, Lucee 5, ColdBox 7 support) warrant a major version bump per semver. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
adobe@2025 Test Results - Coldbox be 1 files 12 suites 34s ⏱️ Results for commit eb23954. ♻️ This comment has been updated with latest results. |
adobe@2025 Test Results - Coldbox ^8 1 files 12 suites 12s ⏱️ Results for commit eb23954. ♻️ This comment has been updated with latest results. |
boxlang-cfml@1 Test Results - Coldbox ^8 1 files 12 suites 14s ⏱️ Results for commit eb23954. ♻️ This comment has been updated with latest results. |
boxlang@1 Test Results - Coldbox be 1 files 12 suites 35s ⏱️ Results for commit eb23954. ♻️ This comment has been updated with latest results. |
lucee@6 Test Results - Coldbox ^8 1 files 12 suites 13s ⏱️ Results for commit eb23954. ♻️ This comment has been updated with latest results. |
boxlang@1 Test Results - Coldbox ^8 1 files 12 suites 34s ⏱️ Results for commit eb23954. ♻️ This comment has been updated with latest results. |
lucee@6 Test Results - Coldbox be 1 files 12 suites 13s ⏱️ Results for commit eb23954. ♻️ This comment has been updated with latest results. |
adobe@2023 Test Results - Coldbox ^8 1 files 12 suites 17s ⏱️ Results for commit eb23954. ♻️ This comment has been updated with latest results. |
adobe@2023 Test Results - Coldbox be 1 files 12 suites 1m 35s ⏱️ Results for commit eb23954. ♻️ This comment has been updated with latest results. |
- AmazonS3Spec.cfc isOldACF() unconditionally read
server.coldfusion.productVersion, which doesn't exist on native
BoxLang's server scope, crashing the whole test bundle on boxlang@1.
Guard with structKeyExists( server, "coldfusion" ) first.
- CI: force-install latest commandbox-cfconfig before starting any
server, since the version bundled with the pinned CommandBox CLI has
no config provider for adobe@2025 yet ("Sorry, no config provider
could be found for [adobe@2025...]").
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
Remaining CI failure: not fixable from this PRAfter the fixes pushed here (Content-Length duplication, All 6 fail identically with: This is an AWS bucket policy (or account-level policy) that now explicitly denies SSE-C uploads, applied uniformly across every dynamically-named test bucket this suite creates. It's not a code bug in this repo — there's no client-side fix that makes AWS accept an upload the bucket policy explicitly denies. It will need one of:
I haven't made that call since it affects test coverage/security posture and I don't have AWS console access to check the policy. Flagging it here rather than leaving it silently red — let me know which direction you'd like and I can push the test-suite change. Generated by Claude Code Generated by Claude Code |
- test-harness/box.json: bump testbox devDependency from "be" to "*"
to get TestBox's isBoxLang()/isLucee()/isAdobe() helpers on a stable
release (7.1.0 also fixes isLucee() incorrectly returning true on
BoxLang).
- AmazonS3Spec.cfc: replace structKeyExists(server, "lucee"),
isNull(server.lucee) and server.keyExists("boxlang") with TestBox's
isAdobe()/isLucee()/isBoxLang().
- The bucket used by CI test runs blocks SSE-C (customer-provided key)
uploads at the policy level. The 6 "customer encryption key" specs
now exercise SSE-S3 (encryptionAlgorithm) instead of SSE-C
(encryptionKey) so they can run against this bucket. The SDK's SSE-C
support itself is unchanged for callers whose bucket allows it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
…O array
- Sv4UtilSpec.cfc: .listToArray() member-function syntax isn't resolved
on Adobe ColdFusion ("The listToArray method was not found"), only on
Lucee/BoxLang. Switched to the portable listToArray(string, delimiter)
function call. This was pre-existing and unrelated to this PR's
changes, but promoting adobe@2023 from experimental to a required
matrix entry surfaced it as a blocking failure.
- AmazonS3.cfc putObjectFile(): the multi-part upload path passed an
untyped, empty CFML array to Files.newByteChannel()'s varargs
OpenOption... parameter. Adobe's stricter Java overload resolution
couldn't match it, throwing inside the surrounding try/catch, which
silently fell back to a non-multipart upload ("can perform a
multi-part upload on a file over 5MB" failing with the response not
containing "multipart"). Now explicitly
javacast("java.nio.file.OpenOption[]", []).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
…ne throw() type - CI: bump Setup Java from 11 to Temurin 17. Adobe ColdFusion 2025's cfpm tooling requires Java 17+ and was failing with UnsupportedClassVersionError (class file version 61.0 vs the supported 55.0) during onServerInstall. - server-boxlang@1.json (native BoxLang): install the bx-esapi module, matching server-boxlang-cfml@1.json. Without it, encodeForURL() (used by Sv4Util.cfc's urlEncodePath()) isn't available, which crashed the entire AmazonS3Spec bundle at beforeAll() with "Function [encodeForURL] not found". - AmazonS3.cfc: several throw() calls omitted an explicit type. Adobe/Lucee default an untyped throw() to type "Application", but BoxLang defaults it to "Custom", breaking tests that assert toThrow( type = "application" ). All now pass type = "Application" explicitly for consistent behavior across engines. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
- server-adobe@2023.json, server-adobe@2025.json: pin javaVersion to openjdk21_jre, matching the BoxLang server configs, so the engine's own JVM is consistent and modern across the matrix. - Sv4UtilSpec.cfc: rename the `file` parameter (in headersFromRequestFile()/urlParamsFromRequestFile()) to `requestContent`. Adobe ColdFusion treats `file` specially in some contexts, throwing "Complex object types cannot be converted to simple values" when it was passed into listToArray(). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
Ported this fix from the already-working coldbox-modules/cbfs server configs. On Java 17+, the module system blocks reflective access to internal JDK packages like sun.nio.fs (which backs java.nio.file.Files) unless explicitly opened via --add-opens. This is very likely the real root cause of two previously-unexplained Adobe failures: the multi-part upload path (which calls java.nio.file.Files.newByteChannel()) silently failing inside a try/catch and falling back to a non-multipart upload, and possibly contributing to slow/flaky adobe@2025 startup. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
Replace the separate Ortus-Solutions/setup-commandbox step plus manual box install --force commandbox-boxlang/commandbox-cfconfig steps with a single ortus-boxlang/setup-boxlang@main step (with-commandbox: true, commandbox_modules: commandbox-boxlang,commandbox-cfconfig, testbox-cli), matching the already-working setup in coldbox-modules/cbfs. Also bump Setup Java from 17 to 21 to match cbfs and the server JVM pins. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
The multi-part upload test on Adobe fails with the response not containing "multipart", meaning putObjectFile() silently fell back to the non-multipart path. The actual exception is caught by an internal try/catch and only passed to a fully-mocked logger in this test, so it's invisible in CI output. Temporarily print the mock's captured error() call log via systemOutput() to see the real exception on the next CI run. To be reverted once the root cause is confirmed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
systemOutput() isn't recognized in this Adobe scripting context
("Variable SYSTEMOUTPUT is undefined"), so the previous diagnostic
attempt itself errored instead of printing anything. Use TestBox's
fail() helper instead, which surfaces its message through the same
"Failure: ..." reporting we already see reliably in CI output.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
Root cause finally confirmed via a temporary diagnostic (now removed): coldfusion.runtime.UndefinedElementException: Element UPLOADID is undefined in PART. putObjectFile()'s multi-part upload path routed concurrent part uploads through variables.asyncManager.allApply(). On Adobe, ColdBox's async cbproxies Function wrapper does not correctly marshal the "part" struct argument across the async boundary, so part.uploadId is missing inside the closure. This exception was silently caught by the surrounding try/catch and fell back to a non-multipart upload, with no visible error - "can perform a multi-part upload on a file over 5MB" only failed with the response not containing "multipart", giving no clue to the real cause. Always use the synchronous part-upload path (the code already had a working, near-identical fallback for engines without an async manager) until this ColdBox/Adobe async interop issue is fixed upstream. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
The async-marshaling fix got the multi-part upload path actually
running on Adobe now (adobe@2023 is fully green), surfacing a
different, smaller issue on adobe@2025: the test asserted the
uploaded object's Content-Length against a file size computed BEFORE
fileWrite() ran ("Expected [6291456] but received [6291457]"). Read
the actual on-disk size via getFileInfo() after writing instead, so
the assertion holds regardless of any engine-specific fileWrite()
byte-count behavior.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
* Fix: BoxLang signature failure — use isNull() instead of structKeyExists(arguments,...) for optional date overrides (#47) * fix: use isNull() instead of structKeyExists(arguments,...) for optional date overrides structKeyExists(arguments, "x") is not a safe way to test whether an optional, no-default argument was passed: on engines with full null support (BoxLang defaults to this, unlike Lucee's default partial null support), an unpassed argument still exists as a key holding null, so structKeyExists() returns true. In generateSignatureData() (Sv4Util.cfc and Sv2Util.cfc), both callers in AmazonS3.cfc omit amzDate and dateStamp entirely, but on BoxLang structKeyExists(arguments, "amzDate") is still true, so the code reads arguments.dateStamp (a real null) and passes it into buildCredentialScope()'s required dateStamp parameter, which BoxLang correctly rejects as missing: Error: Required argument dateStamp is missing for function buildCredentialScope This breaks every signed S3 request (PUT/GET/DELETE/etc.) on the boxlang@1 engine. Check each optional argument independently with isNull() instead, which is null-support-safe on every engine and degrades correctly when only one of the two is actually passed. Applied the same fix to MiniLogBox.cfc's debug/error/warn(), which had the identical structKeyExists(arguments, "data") pattern for its optional data parameter. Note: this repo's own CI matrix (.github/workflows/tests.yml) tests boxlang-cfml@1 but not the native boxlang@1 engine, which is why this went uncaught. * Apply cfformat changes * Fix Content-Length duplication and date format bugs, add native BoxLang support, refresh docs and CI matrix - copyObject()/renameObject(): remove manually-set Content-Length header that duplicated CFHTTP's own header on bodyless requests, causing SignatureDoesNotMatch on Adobe CF and BoxLang - Sv4Util.cfc/Sv2Util.cfc: fix dateFormat() mask from "yyyymmdd" (minutes) to "yyyyMMdd" (month) for cross-engine correctness - Fix server-boxlang-cfml@1.json leftover aliases copied from another module - Add native BoxLang (boxlang@1) server config and CI matrix entry - CI matrix: drop lucee@5, adobe@2018, adobe@2021; add lucee@6, adobe@2023, adobe@2025; bump ColdBox to ^8 - box.json: swap commandbox-dotenv/commandbox-cfconfig devDependencies for commandbox-boxlang; update shortDescription - test-harness/box.json: bump coldbox dependency to ^8 - Rewrite readme.md (BoxLang-first, expanded usage/config/testing docs) and update changelog.md - Add AGENTS.md with engine-portability guidance for coding agents - Run cfformat --overwrite across the project Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk * Bump version to 6.0.0 to target this as a major release Breaking changes in this branch (dropped Adobe 2018/2021, Lucee 5, ColdBox 7 support) warrant a major version bump per semver. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk * Fix native BoxLang test crash and Adobe 2025 CFConfig gap in CI - AmazonS3Spec.cfc isOldACF() unconditionally read server.coldfusion.productVersion, which doesn't exist on native BoxLang's server scope, crashing the whole test bundle on boxlang@1. Guard with structKeyExists( server, "coldfusion" ) first. - CI: force-install latest commandbox-cfconfig before starting any server, since the version bundled with the pinned CommandBox CLI has no config provider for adobe@2025 yet ("Sorry, no config provider could be found for [adobe@2025...]"). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk * Use TestBox engine-detection helpers; switch SSE-C tests to SSE-S3 - test-harness/box.json: bump testbox devDependency from "be" to "*" to get TestBox's isBoxLang()/isLucee()/isAdobe() helpers on a stable release (7.1.0 also fixes isLucee() incorrectly returning true on BoxLang). - AmazonS3Spec.cfc: replace structKeyExists(server, "lucee"), isNull(server.lucee) and server.keyExists("boxlang") with TestBox's isAdobe()/isLucee()/isBoxLang(). - The bucket used by CI test runs blocks SSE-C (customer-provided key) uploads at the policy level. The 6 "customer encryption key" specs now exercise SSE-S3 (encryptionAlgorithm) instead of SSE-C (encryptionKey) so they can run against this bucket. The SDK's SSE-C support itself is unchanged for callers whose bucket allows it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk * Fix Adobe-specific failures: listToArray member syntax and untyped NIO array - Sv4UtilSpec.cfc: .listToArray() member-function syntax isn't resolved on Adobe ColdFusion ("The listToArray method was not found"), only on Lucee/BoxLang. Switched to the portable listToArray(string, delimiter) function call. This was pre-existing and unrelated to this PR's changes, but promoting adobe@2023 from experimental to a required matrix entry surfaced it as a blocking failure. - AmazonS3.cfc putObjectFile(): the multi-part upload path passed an untyped, empty CFML array to Files.newByteChannel()'s varargs OpenOption... parameter. Adobe's stricter Java overload resolution couldn't match it, throwing inside the surrounding try/catch, which silently fell back to a non-multipart upload ("can perform a multi-part upload on a file over 5MB" failing with the response not containing "multipart"). Now explicitly javacast("java.nio.file.OpenOption[]", []). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk * Fix Adobe 2025 Java version, native BoxLang ESAPI gap, and cross-engine throw() type - CI: bump Setup Java from 11 to Temurin 17. Adobe ColdFusion 2025's cfpm tooling requires Java 17+ and was failing with UnsupportedClassVersionError (class file version 61.0 vs the supported 55.0) during onServerInstall. - server-boxlang@1.json (native BoxLang): install the bx-esapi module, matching server-boxlang-cfml@1.json. Without it, encodeForURL() (used by Sv4Util.cfc's urlEncodePath()) isn't available, which crashed the entire AmazonS3Spec bundle at beforeAll() with "Function [encodeForURL] not found". - AmazonS3.cfc: several throw() calls omitted an explicit type. Adobe/Lucee default an untyped throw() to type "Application", but BoxLang defaults it to "Custom", breaking tests that assert toThrow( type = "application" ). All now pass type = "Application" explicitly for consistent behavior across engines. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk * Pin Adobe 2023/2025 to JRE 21; fix reserved-name param on Adobe - server-adobe@2023.json, server-adobe@2025.json: pin javaVersion to openjdk21_jre, matching the BoxLang server configs, so the engine's own JVM is consistent and modern across the matrix. - Sv4UtilSpec.cfc: rename the `file` parameter (in headersFromRequestFile()/urlParamsFromRequestFile()) to `requestContent`. Adobe ColdFusion treats `file` specially in some contexts, throwing "Complex object types cannot be converted to simple values" when it was passed into listToArray(). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk * Add --add-opens java.base/sun.nio.fs JVM arg to Adobe server configs Ported this fix from the already-working coldbox-modules/cbfs server configs. On Java 17+, the module system blocks reflective access to internal JDK packages like sun.nio.fs (which backs java.nio.file.Files) unless explicitly opened via --add-opens. This is very likely the real root cause of two previously-unexplained Adobe failures: the multi-part upload path (which calls java.nio.file.Files.newByteChannel()) silently failing inside a try/catch and falling back to a non-multipart upload, and possibly contributing to slow/flaky adobe@2025 startup. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk * CI: use ortus-boxlang/setup-boxlang action, matching cbfs Replace the separate Ortus-Solutions/setup-commandbox step plus manual box install --force commandbox-boxlang/commandbox-cfconfig steps with a single ortus-boxlang/setup-boxlang@main step (with-commandbox: true, commandbox_modules: commandbox-boxlang,commandbox-cfconfig, testbox-cli), matching the already-working setup in coldbox-modules/cbfs. Also bump Setup Java from 17 to 21 to match cbfs and the server JVM pins. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk * TEMP: print swallowed multipart exception for CI diagnosis The multi-part upload test on Adobe fails with the response not containing "multipart", meaning putObjectFile() silently fell back to the non-multipart path. The actual exception is caught by an internal try/catch and only passed to a fully-mocked logger in this test, so it's invisible in CI output. Temporarily print the mock's captured error() call log via systemOutput() to see the real exception on the next CI run. To be reverted once the root cause is confirmed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk * TEMP: fix diagnostic - systemOutput() undefined on Adobe, use fail() systemOutput() isn't recognized in this Adobe scripting context ("Variable SYSTEMOUTPUT is undefined"), so the previous diagnostic attempt itself errored instead of printing anything. Use TestBox's fail() helper instead, which surfaces its message through the same "Failure: ..." reporting we already see reliably in CI output. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk * Apply cfformat changes * Fix multi-part upload on Adobe: bypass broken async closure marshaling Root cause finally confirmed via a temporary diagnostic (now removed): coldfusion.runtime.UndefinedElementException: Element UPLOADID is undefined in PART. putObjectFile()'s multi-part upload path routed concurrent part uploads through variables.asyncManager.allApply(). On Adobe, ColdBox's async cbproxies Function wrapper does not correctly marshal the "part" struct argument across the async boundary, so part.uploadId is missing inside the closure. This exception was silently caught by the surrounding try/catch and fell back to a non-multipart upload, with no visible error - "can perform a multi-part upload on a file over 5MB" only failed with the response not containing "multipart", giving no clue to the real cause. Always use the synchronous part-upload path (the code already had a working, near-identical fallback for engines without an async manager) until this ColdBox/Adobe async interop issue is fixed upstream. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk * Fix off-by-one Content-Length assertion in multipart test on Adobe 2025 The async-marshaling fix got the multi-part upload path actually running on Adobe now (adobe@2023 is fully green), surfacing a different, smaller issue on adobe@2025: the test asserted the uploaded object's Content-Length against a file size computed BEFORE fileWrite() ran ("Expected [6291456] but received [6291457]"). Read the actual on-disk size via getFileInfo() after writing instead, so the assertion holds regardless of any engine-specific fileWrite() byte-count behavior. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk * finalized ai integrations * more updates * updated to module standards --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: lmajano <lmajano@users.noreply.github.com> * fix markdown issues * updates --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: lmajano <lmajano@users.noreply.github.com>
Summary
Every signed S3 request (PUT/GET/DELETE/etc.) fails on the
boxlang@1engine with:Root cause
In
generateSignatureData()(Sv4Util.cfcand the equivalent inSv2Util.cfc),amzDateanddateStampare optional parameters with no default:Both call sites in
AmazonS3.cfc(s3Request()andgetAuthenticatedURL()) omit both entirely, relying on the function to generate them internally. The override check was:if ( structKeyExists( arguments, "amzDate" ) || structKeyExists( arguments, "dateStamp" ) ) { props.dateStamp = arguments.dateStamp; props.amzDate = arguments.amzDate; }structKeyExists(arguments, "x")is not a safe way to test "was this optional, no-default argument passed" across engines. On engines with full null support — which is BoxLang's default (unlike Lucee's default partial null support) — an unpassed, no-default argument still exists as a key holdingnull, sostructKeyExists()returnstruefor it. That makes theifbranch run even though neither argument was actually passed, soprops.dateStamp = arguments.dateStampassigns a realnull. Thatnullthen flows intobuildCredentialScope( required string dateStamp, ... ), which BoxLang correctly rejects as a missing required argument.Lucee/Adobe don't hit this because with their default null handling, an unpassed no-default argument simply isn't a key in
argumentsat all, sostructKeyExists()correctly returnsfalse.Fix
Check each optional argument independently with
isNull(), which works correctly regardless of an engine's null-support model, and also correctly handles the case where only one of the two is passed (the original code would have blindly read the other asnullin that case too).Applied the identical fix to
MiniLogBox.cfc'sdebug()/error()/warn(), which had the samestructKeyExists( arguments, "data" )pattern for its optionaldataparameter — same root cause, lower-severity symptom (silently logs a spuriousnullentry instead of throwing, sincedataisn't arequireddownstream argument).Other BoxLang findings
This repo's own CI matrix (
.github/workflows/tests.yml) testsboxlang-cfml@1(BoxLang's CFML-compatibility mode) but not the nativeboxlang@1engine, which is why this went uncaught —boxlang-cfml@1's null-handling compatibility shim apparently masks it. A grep acrossmodels/**/*.cfcfor thestructKeyExists( arguments, ... )anti-pattern turned up no other occurrences beyond the ones fixed here.Test plan
boxlang@1(this was discovered via coldbox-modules/cbfs#57, which pulls this module and can be used to verify)🤖 Generated with Claude Code
https://claude.ai/code/session_01MY8vKDaEubRApVMT9BXSYk
Generated by Claude Code