Skip to content

ARSN-642: prepare Arsenal to run on Node 24 - #2709

Open
francoisferrand wants to merge 4 commits into
development/8.6from
improvement/ARSN-642
Open

francoisferrand wants to merge 4 commits into
development/8.6from
improvement/ARSN-642

Conversation

@francoisferrand

Copy link
Copy Markdown
Contributor

Node 22 enters Maintenance in Oct 2026 and reaches end-of-life 30 April 2027. Node 24 is Active LTS until April 2028, so it's time to get Arsenal running there.

CI

tests.yaml now runs a Node 22/24 matrix (compile/lint/KMIP jobs move fully to 24; Codecov upload stays on the 24 leg). Keeping 22 in the mix a while longer since cloudserver, backbeat and scuba are still on it during this transition.

engines.node -> >=22

Was >=20, which went EOL in April 2026 and wasn't being tested anymore. Deliberately not going to >=24 yet — cloudserver, backbeat and scuba need to move first, or Node 22 needs to go EOL (April 2027), whichever comes first.

url.parse() removal

url.parse() is runtime-deprecated (DEP0169). Six call sites replaced.

Three are straight swaps to new URL(). Three needed a purpose-built parser (lib/utils/requestUrl.ts) instead, because new URL() normalizes in ways that change an S3 request path: it collapses ./.. segments, reads a leading // as an authority, and percent-encodes non-ASCII. /bucket/a/../b becomes /bucket/b; //bucket/key loses its bucket. On getCanonicalizedResource.ts (v2 signature path) that would change what gets signed — a request could end up verified against a different resource than it addresses. Supplying a base doesn't help either: absolute URLs ignore it entirely.

parseRequestTarget() reproduces the legacy parser's behavior for these shapes (differentially tested against real url.parse() output, hundreds of thousands of cases, zero mismatches) without ever resolving a scheme or host. Exported it from Arsenal's index so cloudserver/backbeat can use the same helper for their own url.parse() removals, since they have the identical hazard (copy-source header, routeBackbeat).

Scality dependency refresh

Bumped once each of them had a Node 24-ready release: fcntl 0.3.1, httpagent 1.1.1, sproxydclient 8.2.3 (now tagged, previously pinned by commit), werelogs 8.2.5, @scality/eslint-config-scality 8.3.3. Lockfile refreshed accordingly.

Verification

  • Unit suite green on Node 22 and Node 24 (167 suites, 4006 passed, 9 skipped, run sequentially post-rebase to avoid MongoMemoryServer port contention).
  • Build and lint pass on Node 24.
  • yarn audit before/after: prod advisories unchanged (65, none of the bumped Scality packages carried any); dev advisories dropped from 52 to 48 — 4 DoS advisories fixed via the Guidelines 8.3.3 refresh dropping its old markdown-it/linkify-it chain.

Out of scope

Deprecated dependency cleanup (level, ioctl, prom-client, ajv, @types/ioredis) and publishing — tracked separately.

Issue: ARSN-642

Update CI coverage and refresh the Scality dependency set for the Node 24 transition while retaining Node 22 compatibility. Synchronize the lockfile and stabilize the health probe setup on the newer runtime.

Issue: ARSN-642
Replace deprecated URL parsing while preserving raw S3 path semantics for routing, metadata, and v2 signature canonicalization. Export the shared parser for consumers that handle client-supplied request targets.

Issue: ARSN-642
@bert-e

bert-e commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Hello francoisferrand,

My role is to assist you with the merge of this
pull request. Please type @bert-e help to get information
on this process, or consult the user documentation.

Available options
name description privileged authored
/after_pull_request Wait for the given pull request id to be merged before continuing with the current one.
/bypass_author_approval Bypass the pull request author's approval
/bypass_build_status Bypass the build and test status
/bypass_commit_size Bypass the check on the size of the changeset TBA
/bypass_incompatible_branch Bypass the check on the source branch prefix
/bypass_jira_check Bypass the Jira issue check
/bypass_peer_approval Bypass the pull request peers' approval
/bypass_leader_approval Bypass the pull request leaders' approval
/bypass_source_branch_lineage Bypass the cross-branch contamination check
/approve Instruct Bert-E that the author has approved the pull request. ✍️
/create_pull_requests Allow the creation of integration pull requests.
/create_integration_branches Allow the creation of integration branches.
/no_octopus Prevent Wall-E from doing any octopus merge and use multiple consecutive merge instead
/unanimity Change review acceptance criteria from one reviewer at least to all reviewers
/wait Instruct Bert-E not to run until further notice.
Available commands
name description privileged
/help Print Bert-E's manual in the pull request.
/status Print Bert-E's current status in the pull request.
/clear Remove all comments from Bert-E from the history TBA
/retry Re-start a fresh build TBA
/build Re-start a fresh build TBA
/force_reset Delete integration branches & pull requests, and restart merge process from the beginning.
/reset Try to remove integration branches unless there are commits on them which do not appear on the source branch.

Status report is not available.

@francoisferrand
francoisferrand changed the base branch from development/8.5 to development/8.6 September 21, 2026 16:05
@bert-e

bert-e commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Waiting for approval

The following approvals are needed before I can proceed with the merge:

  • the author

  • 2 peers

matrix:
# 24 is the target runtime; 22 is what engines.node still allows and
# what cloudserver/backbeat/scuba run until they move over.
node-version: ['22', '24']

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Btw you used this in a lot of repo recently but it means every tests will run twice 🤔 You could've put 24 directly 🤔 , I guess the few remaining repo on node 22 will soon be updated considering you do like one repo per day 🤔

Comment thread lib/utils/requestUrl.ts
@@ -0,0 +1,96 @@
/**
* Splitting of request targets (`/bucket/key?acl`) without `url.parse()`, which

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A bit heavy to read, while parseRequestTarget could use one or two input->output examples

});

it('should leave a non-ASCII key unencoded', () => {
assert.strictEqual(resourceFor('/bucket/ключ'), '/bucket/ключ');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

😆

const { parseRequestTarget } = require('../../../lib/utils/requestUrl');

/*
* Expected values below were captured from the `url.parse()` this replaces, so

@SylvainSenechal SylvainSenechal Sep 21, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Its nit and more of a remark, connected to the other new file requestUrl.ts

I notice claude likes to make comment referencing stuff that it just removed, it's okish in the context of the pr, but for the codebase it's weird,
It feels like its outputing its thought context into the comments. I'm talking about the "were captured from the url.parse() this repllaces", not just for this pr but something i notice in general, I don't think this is super good to keep written this way.

@codecov

codecov Bot commented Sep 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.14286% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.75%. Comparing base (1ed7c25) to head (3006f5a).

Files with missing lines Patch % Lines
lib/storage/data/LocationConstraintParser.js 41.17% 10 Missing ⚠️
lib/network/rest/utils.ts 57.14% 3 Missing ⚠️
lib/network/rest/RESTServer.ts 93.33% 1 Missing ⚠️
lib/storage/metadata/proxy/utils.js 91.66% 1 Missing ⚠️
Additional details and impacted files
@@                 Coverage Diff                 @@
##           development/8.6    #2709      +/-   ##
===================================================
- Coverage            74.76%   74.75%   -0.01%     
===================================================
  Files                  227      228       +1     
  Lines                18650    18673      +23     
  Branches              3864     3873       +9     
===================================================
+ Hits                 13943    13959      +16     
- Misses                4702     4709       +7     
  Partials                 5        5              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Malformed table row was missing 3 of its 4 cells, tripping markdownlint's
MD056 and blocking the test job before any tests ran. Also cleaned up
code fence spacing and missing semicolons/commas in the JS examples,
which prettier was flagging now that this file is part of the diff.

The 'Unified at v17' row was never really a 4-column table row (that's
part of why it was malformed): it's a single summary line. Moving it
out to a plain sentence below the table removes it as the widest cell
in the first column, which is what was pushing prettier's table padding
past markdownlint's 80-char line limit. Table data and field names are
otherwise untouched, just repadded to prettier's formatting.

Issue: ARSN-642
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.

3 participants