update dependencies, rebuild

This commit is contained in:
Arpad Borsos
2026-07-26 16:34:10 +02:00
parent 0e24e5dcec
commit 9f151aca7c
14 changed files with 5617 additions and 2892 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+417 -128
View File
@@ -2692,7 +2692,13 @@ function requireRequest$1 () {
} else if (typeof val[i] === 'object') { } else if (typeof val[i] === 'object') {
throw new InvalidArgumentError(`invalid ${key} header`) throw new InvalidArgumentError(`invalid ${key} header`)
} else { } else {
arr.push(`${val[i]}`); // Coerce primitives (and reject unsafe coercions such as functions
// with a crafted toString/Symbol.toPrimitive).
const str = `${val[i]}`;
if (!isValidHeaderValue(str)) {
throw new InvalidArgumentError(`invalid ${key} header`)
}
arr.push(str);
} }
} }
val = arr; val = arr;
@@ -2703,7 +2709,12 @@ function requireRequest$1 () {
} else if (val === null) { } else if (val === null) {
val = ''; val = '';
} else { } else {
// Coerce primitives (and reject unsafe coercions such as functions
// with a crafted toString/Symbol.toPrimitive).
val = `${val}`; val = `${val}`;
if (!isValidHeaderValue(val)) {
throw new InvalidArgumentError(`invalid ${key} header`)
}
} }
if (headerName === 'host') { if (headerName === 'host') {
@@ -2854,6 +2865,7 @@ function requireDispatcherBase () {
get webSocketOptions () { get webSocketOptions () {
return { return {
maxFragments: this[kWebSocketOptions].maxFragments ?? 131072,
maxPayloadSize: this[kWebSocketOptions].maxPayloadSize ?? 128 * 1024 * 1024 maxPayloadSize: this[kWebSocketOptions].maxPayloadSize ?? 128 * 1024 * 1024
} }
} }
@@ -8758,6 +8770,7 @@ function requireClientH1 () {
RequestContentLengthMismatchError, RequestContentLengthMismatchError,
ResponseContentLengthMismatchError, ResponseContentLengthMismatchError,
RequestAbortedError, RequestAbortedError,
InvalidArgumentError,
HeadersTimeoutError, HeadersTimeoutError,
HeadersOverflowError, HeadersOverflowError,
SocketError, SocketError,
@@ -8805,6 +8818,9 @@ function requireClientH1 () {
const FastBuffer = Buffer[Symbol.species]; const FastBuffer = Buffer[Symbol.species];
const addListener = util.addListener; const addListener = util.addListener;
const removeAllListeners = util.removeAllListeners; const removeAllListeners = util.removeAllListeners;
const kIdleSocketValidation = Symbol('kIdleSocketValidation');
const kIdleSocketValidationTimeout = Symbol('kIdleSocketValidationTimeout');
const kSocketUsed = Symbol('kSocketUsed');
let extractBody; let extractBody;
@@ -9119,6 +9135,11 @@ function requireClientH1 () {
return -1 return -1
} }
if (client[kRunning] === 0) {
util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket)));
return -1
}
const request = client[kQueue][client[kRunningIdx]]; const request = client[kQueue][client[kRunningIdx]];
if (!request) { if (!request) {
return -1 return -1
@@ -9222,6 +9243,11 @@ function requireClientH1 () {
return -1 return -1
} }
if (client[kRunning] === 0) {
util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket)));
return -1
}
const request = client[kQueue][client[kRunningIdx]]; const request = client[kQueue][client[kRunningIdx]];
/* istanbul ignore next: difficult to make a test case for */ /* istanbul ignore next: difficult to make a test case for */
@@ -9395,6 +9421,7 @@ function requireClientH1 () {
request.onComplete(headers); request.onComplete(headers);
client[kQueue][client[kRunningIdx]++] = null; client[kQueue][client[kRunningIdx]++] = null;
socket[kSocketUsed] = true;
if (socket[kWriting]) { if (socket[kWriting]) {
assert(client[kRunning] === 0); assert(client[kRunning] === 0);
@@ -9453,6 +9480,9 @@ function requireClientH1 () {
socket[kWriting] = false; socket[kWriting] = false;
socket[kReset] = false; socket[kReset] = false;
socket[kBlocking] = false; socket[kBlocking] = false;
socket[kIdleSocketValidation] = 0;
socket[kIdleSocketValidationTimeout] = null;
socket[kSocketUsed] = false;
socket[kParser] = new Parser(client, socket, llhttpInstance); socket[kParser] = new Parser(client, socket, llhttpInstance);
addListener(socket, 'error', function (err) { addListener(socket, 'error', function (err) {
@@ -9499,6 +9529,8 @@ function requireClientH1 () {
const client = this[kClient]; const client = this[kClient];
const parser = this[kParser]; const parser = this[kParser];
clearIdleSocketValidation(this);
if (parser) { if (parser) {
if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) {
this[kError] = parser.finish() || this[kError]; this[kError] = parser.finish() || this[kError];
@@ -9564,7 +9596,7 @@ function requireClientH1 () {
return socket.destroyed return socket.destroyed
}, },
busy (request) { busy (request) {
if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) {
return true return true
} }
@@ -9602,6 +9634,31 @@ function requireClientH1 () {
} }
} }
function clearIdleSocketValidation (socket) {
if (socket[kIdleSocketValidationTimeout]) {
clearTimeout(socket[kIdleSocketValidationTimeout]);
socket[kIdleSocketValidationTimeout] = null;
}
socket[kIdleSocketValidation] = 0;
}
function scheduleIdleSocketValidation (client, socket) {
socket[kIdleSocketValidation] = 1;
socket[kIdleSocketValidationTimeout] = setTimeout(() => {
socket[kIdleSocketValidationTimeout] = null;
socket[kIdleSocketValidation] = 2;
if (client[kSocket] === socket && !socket.destroyed) {
client[kResume]();
}
}, 0);
socket[kIdleSocketValidationTimeout].unref?.();
}
/**
* @param {import('./client.js')} client
*/
function resumeH1 (client) { function resumeH1 (client) {
const socket = client[kSocket]; const socket = client[kSocket];
@@ -9616,6 +9673,32 @@ function requireClientH1 () {
socket[kNoRef] = false; socket[kNoRef] = false;
} }
if (client[kRunning] === 0 && client[kPending] > 0 && socket[kSocketUsed]) {
if (socket[kIdleSocketValidation] === 0) {
scheduleIdleSocketValidation(client, socket);
socket[kParser].readMore();
if (socket.destroyed) {
return
}
return
}
if (socket[kIdleSocketValidation] === 1) {
socket[kParser].readMore();
if (socket.destroyed) {
return
}
return
}
}
if (client[kRunning] === 0) {
socket[kParser].readMore();
if (socket.destroyed) {
return
}
}
if (client[kSize] === 0) { if (client[kSize] === 0) {
if (socket[kParser].timeoutType !== TIMEOUT_KEEP_ALIVE) { if (socket[kParser].timeoutType !== TIMEOUT_KEEP_ALIVE) {
socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_KEEP_ALIVE); socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_KEEP_ALIVE);
@@ -9671,8 +9754,16 @@ function requireClientH1 () {
} }
body = bodyStream.stream; body = bodyStream.stream;
contentLength = bodyStream.length; contentLength = bodyStream.length;
} else if (util.isBlobLike(body) && request.contentType == null && body.type) { } else if (util.isBlobLike(body) && request.contentType == null) {
headers.push('content-type', body.type); const contentType = body.type;
if (contentType) {
const contentTypeValue = `${contentType}`;
if (!util.isValidHeaderValue(contentTypeValue)) {
util.errorRequest(client, request, new InvalidArgumentError('invalid content-type header'));
return false
}
headers.push('content-type', contentTypeValue);
}
} }
if (body && typeof body.read === 'function') { if (body && typeof body.read === 'function') {
@@ -9709,6 +9800,7 @@ function requireClientH1 () {
} }
const socket = client[kSocket]; const socket = client[kSocket];
clearIdleSocketValidation(socket);
const abort = (err) => { const abort = (err) => {
if (request.aborted || request.completed) { if (request.aborted || request.completed) {
@@ -13106,6 +13198,28 @@ function requireRetryHandler () {
return new Date(retryAfter).getTime() - current return new Date(retryAfter).getTime() - current
} }
function validatePartialResponseContentLength (headers, range, statusCode, retryCount) {
const contentLength = headers['content-length'];
if (contentLength == null) {
return null
}
if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) {
return null
}
const length = Number(contentLength);
const expectedLength = range.end - range.start + 1;
if (!Number.isFinite(length) || length !== expectedLength) {
return new RequestRetryError('Content-Length mismatch', statusCode, {
headers,
data: { count: retryCount }
})
}
return null
}
class RetryHandler { class RetryHandler {
constructor (opts, handlers) { constructor (opts, handlers) {
const { retryOptions, ...dispatchOpts } = opts; const { retryOptions, ...dispatchOpts } = opts;
@@ -13320,6 +13434,12 @@ function requireRetryHandler () {
return false return false
} }
const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount);
if (contentLengthError != null) {
this.abort(contentLengthError);
return false
}
const { start, size, end = size - 1 } = contentRange; const { start, size, end = size - 1 } = contentRange;
assert(this.start === start, 'content-range mismatch'); assert(this.start === start, 'content-range mismatch');
@@ -13343,6 +13463,12 @@ function requireRetryHandler () {
) )
} }
const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount);
if (contentLengthError != null) {
this.abort(contentLengthError);
return false
}
const { start, size, end = size - 1 } = range; const { start, size, end = size - 1 } = range;
assert( assert(
start != null && Number.isFinite(start), start != null && Number.isFinite(start),
@@ -23731,7 +23857,7 @@ function requireUtil$2 () {
if ( if (
code < 0x20 || // exclude CTLs (0-31) code < 0x20 || // exclude CTLs (0-31)
code === 0x7F || // DEL code > 0x7E || // exclude DEL and non-ascii
code === 0x3B // ; code === 0x3B // ;
) { ) {
throw new Error('Invalid cookie path') throw new Error('Invalid cookie path')
@@ -23740,16 +23866,80 @@ function requireUtil$2 () {
} }
/** /**
* I have no idea why these values aren't allowed to be honest, * <let-dig> ::= <letter> | <digit>
* but Deno tests these. - Khafra *
* <letter> ::= any one of the 52 alphabetic characters A through Z in
* upper case and a through z in lower case
*
* <digit> ::= any one of the ten digits 0 through 9r
*
* @see https://www.rfc-editor.org/rfc/rfc1034#section-3.5
* @param {number} code
*/
function isLetterOrDigit (code) {
return (
(code >= 0x30 && code <= 0x39) || // 0-9
(code >= 0x41 && code <= 0x5A) || // A-Z
(code >= 0x61 && code <= 0x7A) // a-z
)
}
/**
* Validates a cookie domain against the "preferred name syntax".
*
* <domain> ::= <subdomain> | " "
* <subdomain> ::= <label> | <subdomain> "." <label>
* <label> ::= <let-dig> [ [ <ldh-str> ] <let-dig> ]
* <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
* <let-dig-hyp> ::= <let-dig> | "-"
*
* @see https://www.rfc-editor.org/rfc/rfc1034#section-3.5
* @see https://www.rfc-editor.org/rfc/rfc1123#section-2.1
* @see https://www.rfc-editor.org/rfc/rfc1035#section-2.3.4
* @param {string} domain * @param {string} domain
*/ */
function validateCookieDomain (domain) { function validateCookieDomain (domain) {
if ( // <domain> ::= <subdomain> | " "
domain.startsWith('-') || if (domain === ' ') {
domain.endsWith('.') || return
domain.endsWith('-') }
) {
if (domain.length > 255) {
throw new Error('Invalid cookie domain')
}
let labelLength = 0;
for (let i = 0; i < domain.length; ++i) {
const code = domain.charCodeAt(i);
if (code === 0x2E) {
if (labelLength === 0) {
throw new Error('Invalid cookie domain')
}
if (domain.charCodeAt(i - 1) === 0x2D) { // "-"
throw new Error('Invalid cookie domain')
}
labelLength = 0;
continue
}
if (labelLength === 0 && !isLetterOrDigit(code)) {
throw new Error('Invalid cookie domain')
}
if (!isLetterOrDigit(code) && code !== 0x2D) { // "-"
throw new Error('Invalid cookie domain')
}
if (++labelLength > 63) {
throw new Error('Invalid cookie domain')
}
}
if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 0x2D) { // "-"
throw new Error('Invalid cookie domain') throw new Error('Invalid cookie domain')
} }
} }
@@ -23892,7 +24082,13 @@ function requireUtil$2 () {
const [key, ...value] = part.split('='); const [key, ...value] = part.split('=');
out.push(`${key.trim()}=${value.join('=')}`); const trimmedKey = key.trim();
const joinedValue = value.join('=');
validateCookieName(trimmedKey);
validateCookieValue(joinedValue);
out.push(`${trimmedKey}=${joinedValue}`);
} }
return out.join('; ') return out.join('; ')
@@ -24191,32 +24387,25 @@ function requireParse () {
// If the attribute-name case-insensitively matches the string // If the attribute-name case-insensitively matches the string
// "SameSite", the user agent MUST process the cookie-av as follows: // "SameSite", the user agent MUST process the cookie-av as follows:
// 1. Let enforcement be "Default".
let enforcement = 'Default';
const attributeValueLowercase = attributeValue.toLowerCase(); const attributeValueLowercase = attributeValue.toLowerCase();
// 2. If cookie-av's attribute-value is a case-insensitive match for
// "None", set enforcement to "None".
if (attributeValueLowercase.includes('none')) {
enforcement = 'None';
}
// 3. If cookie-av's attribute-value is a case-insensitive match for // 1. If cookie-av's attribute-value is a case-insensitive match for
// "Strict", set enforcement to "Strict". // "None", append an attribute to the cookie-attribute-list with an
if (attributeValueLowercase.includes('strict')) { // attribute-name of "SameSite" and an attribute-value of "None".
enforcement = 'Strict'; if (attributeValueLowercase === 'none') {
cookieAttributeList.sameSite = 'None';
} else if (attributeValueLowercase === 'strict') {
// 2. If cookie-av's attribute-value is a case-insensitive match for
// "Strict", append an attribute to the cookie-attribute-list with
// an attribute-name of "SameSite" and an attribute-value of
// "Strict".
cookieAttributeList.sameSite = 'Strict';
} else if (attributeValueLowercase === 'lax') {
// 3. If cookie-av's attribute-value is a case-insensitive match for
// "Lax", append an attribute to the cookie-attribute-list with an
// attribute-name of "SameSite" and an attribute-value of "Lax".
cookieAttributeList.sameSite = 'Lax';
} }
// 4. If cookie-av's attribute-value is a case-insensitive match for
// "Lax", set enforcement to "Lax".
if (attributeValueLowercase.includes('lax')) {
enforcement = 'Lax';
}
// 5. Append an attribute to the cookie-attribute-list with an
// attribute-name of "SameSite" and an attribute-value of
// enforcement.
cookieAttributeList.sameSite = enforcement;
} else { } else {
cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed ??= [];
@@ -25802,6 +25991,11 @@ function requireReceiver () {
const { PerMessageDeflate } = requirePermessageDeflate(); const { PerMessageDeflate } = requirePermessageDeflate();
const { MessageSizeExceededError } = requireErrors(); const { MessageSizeExceededError } = requireErrors();
function failWebsocketConnectionWithCode (ws, code, reason) {
closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason));
failWebsocketConnection(ws, reason);
}
// This code was influenced by ws released under the MIT license. // This code was influenced by ws released under the MIT license.
// Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com> // Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
// Copyright (c) 2013 Arnout Kazemier and contributors // Copyright (c) 2013 Arnout Kazemier and contributors
@@ -25821,19 +26015,23 @@ function requireReceiver () {
/** @type {Map<string, PerMessageDeflate>} */ /** @type {Map<string, PerMessageDeflate>} */
#extensions #extensions
/** @type {number} */
#maxFragments
/** @type {number} */ /** @type {number} */
#maxPayloadSize #maxPayloadSize
/** /**
* @param {import('./websocket').WebSocket} ws * @param {import('./websocket').WebSocket} ws
* @param {Map<string, string>|null} extensions * @param {Map<string, string>|null} extensions
* @param {{ maxPayloadSize?: number }} [options] * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options]
*/ */
constructor (ws, extensions, options = {}) { constructor (ws, extensions, options = {}) {
super(); super();
this.ws = ws; this.ws = ws;
this.#extensions = extensions == null ? new Map() : extensions; this.#extensions = extensions == null ? new Map() : extensions;
this.#maxFragments = options.maxFragments ?? 0;
this.#maxPayloadSize = options.maxPayloadSize ?? 0; this.#maxPayloadSize = options.maxPayloadSize ?? 0;
if (this.#extensions.has('permessage-deflate')) { if (this.#extensions.has('permessage-deflate')) {
@@ -25857,9 +26055,9 @@ function requireReceiver () {
if ( if (
this.#maxPayloadSize > 0 && this.#maxPayloadSize > 0 &&
!isControlFrame(this.#info.opcode) && !isControlFrame(this.#info.opcode) &&
this.#info.payloadLength > this.#maxPayloadSize this.#info.payloadLength + this.#fragmentsBytes > this.#maxPayloadSize
) { ) {
failWebsocketConnection(this.ws, 'Payload size exceeds maximum allowed size'); failWebsocketConnectionWithCode(this.ws, 1009, 'Payload size exceeds maximum allowed size');
return false return false
} }
@@ -26024,10 +26222,12 @@ function requireReceiver () {
this.#state = parserStates.INFO; this.#state = parserStates.INFO;
} else { } else {
if (!this.#info.compressed) { if (!this.#info.compressed) {
this.writeFragments(body); if (!this.writeFragments(body)) {
return
}
if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
failWebsocketConnection(this.ws, new MessageSizeExceededError().message); failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message);
return return
} }
@@ -26046,14 +26246,17 @@ function requireReceiver () {
this.#info.fin, this.#info.fin,
(error, data) => { (error, data) => {
if (error) { if (error) {
failWebsocketConnection(this.ws, error.message); const code = error instanceof MessageSizeExceededError ? 1009 : 1007;
failWebsocketConnectionWithCode(this.ws, code, error.message);
return return
} }
this.writeFragments(data); if (!this.writeFragments(data)) {
return
}
if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
failWebsocketConnection(this.ws, new MessageSizeExceededError().message); failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message);
return return
} }
@@ -26123,8 +26326,17 @@ function requireReceiver () {
} }
writeFragments (fragment) { writeFragments (fragment) {
if (
this.#maxFragments > 0 &&
this.#fragments.length === this.#maxFragments
) {
failWebsocketConnectionWithCode(this.ws, 1008, 'Too many message fragments');
return false
}
this.#fragmentsBytes += fragment.length; this.#fragmentsBytes += fragment.length;
this.#fragments.push(fragment); this.#fragments.push(fragment);
return true
} }
consumeFragments () { consumeFragments () {
@@ -26827,9 +27039,12 @@ function requireWebsocket () {
// once this happens, the connection is open // once this happens, the connection is open
this[kResponse] = response; this[kResponse] = response;
const maxPayloadSize = this[kController]?.dispatcher?.webSocketOptions?.maxPayloadSize; const webSocketOptions = this[kController]?.dispatcher?.webSocketOptions;
const maxFragments = webSocketOptions?.maxFragments;
const maxPayloadSize = webSocketOptions?.maxPayloadSize;
const parser = new ByteParser(this, parsedExtensions, { const parser = new ByteParser(this, parsedExtensions, {
maxFragments,
maxPayloadSize maxPayloadSize
}); });
parser.on('drain', onParserDrain); parser.on('drain', onParserDrain);
@@ -30275,6 +30490,17 @@ const closePattern = /\\}/g;
const commaPattern = /\\,/g; const commaPattern = /\\,/g;
const periodPattern = /\\\./g; const periodPattern = /\\\./g;
const EXPANSION_MAX = 100_000; const EXPANSION_MAX = 100_000;
// `EXPANSION_MAX` caps the *number* of expansions, but not their length. An
// input like `'{a,b}'.repeat(1500)` stays under that count - its output is
// truncated to 100k results - while making every result ~1500 characters
// long. The result set, and the intermediate arrays built while combining
// brace sets, then grow large enough to exhaust memory and crash the process
// (CVE-2026-14257). `EXPANSION_MAX_LENGTH` bounds the total number of
// characters the accumulator may hold at any point, so memory stays flat no
// matter how many brace groups are chained. The limit sits well above any
// realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M
// characters) so legitimate input is unaffected.
const EXPANSION_MAX_LENGTH = 4_000_000;
function numeric(str) { function numeric(str) {
return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0); return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
} }
@@ -30323,7 +30549,7 @@ function expand(str, options = {}) {
if (!str) { if (!str) {
return []; return [];
} }
const { max = EXPANSION_MAX } = options; const { max = EXPANSION_MAX, maxLength = EXPANSION_MAX_LENGTH } = options;
// I don't know why Bash 4.3 does this, but it does. // I don't know why Bash 4.3 does this, but it does.
// Anything starting with {} will have the first two bytes preserved // Anything starting with {} will have the first two bytes preserved
// but *only* at the top level, so {},a}b will not expand to anything, // but *only* at the top level, so {},a}b will not expand to anything,
@@ -30333,7 +30559,7 @@ function expand(str, options = {}) {
if (str.slice(0, 2) === '{}') { if (str.slice(0, 2) === '{}') {
str = '\\{\\}' + str.slice(2); str = '\\{\\}' + str.slice(2);
} }
return expand_(escapeBraces(str), max, true).map(unescapeBraces); return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
} }
function embrace(str) { function embrace(str) {
return '{' + str + '}'; return '{' + str + '}';
@@ -30347,22 +30573,113 @@ function lte(i, y) {
function gte(i, y) { function gte(i, y) {
return i >= y; return i >= y;
} }
function expand_(str, max, isTop) { // Build `{ acc[a] + pre + values[v] }` for every combination, capping the
/** @type {string[]} */ // number of results at `max` and the total number of characters at `maxLength`.
const expansions = []; // This is the one place output grows, so bounding it here keeps the single
const m = balanced('{', '}', str); // accumulator - and therefore memory - flat regardless of how many brace groups
if (!m) // are combined (CVE-2026-14257).
return [str]; function combine(acc, pre, values, max, maxLength, dropEmpties) {
// no need to expand pre, since it is guaranteed to be free of brace-sets const out = [];
const pre = m.pre; let length = 0;
const post = m.post.length ? expand_(m.post, max, false) : ['']; for (let a = 0; a < acc.length; a++) {
if (/\$$/.test(m.pre)) { for (let v = 0; v < values.length; v++) {
for (let k = 0; k < post.length && k < max; k++) { if (out.length >= max)
const expansion = pre + '{' + m.body + '}' + post[k]; return out;
expansions.push(expansion); const expansion = acc[a] + pre + values[v];
// Bash drops empty results at the top level. Skip them before they count
// against `max`, so `max` bounds the number of *kept* results.
if (dropEmpties && !expansion)
continue;
if (length + expansion.length > maxLength)
return out;
out.push(expansion);
length += expansion.length;
} }
} }
else { return out;
}
// The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)
// sequence body.
function expandSequence(body, isAlphaSequence, max) {
const n = body.split(/\.\./);
const N = [];
// A sequence body always splits into two or three parts, but the compiler
// can't know that.
/* c8 ignore start */
if (n[0] === undefined || n[1] === undefined) {
return N;
}
/* c8 ignore stop */
const x = numeric(n[0]);
const y = numeric(n[1]);
const width = Math.max(n[0].length, n[1].length);
let incr = n.length === 3 && n[2] !== undefined ?
Math.max(Math.abs(numeric(n[2])), 1)
: 1;
let test = lte;
const reverse = y < x;
if (reverse) {
incr *= -1;
test = gte;
}
const pad = n.some(isPadded);
for (let i = x; test(i, y) && N.length < max; i += incr) {
let c;
if (isAlphaSequence) {
c = String.fromCharCode(i);
if (c === '\\') {
c = '';
}
}
else {
c = String(i);
if (pad) {
const need = width - c.length;
if (need > 0) {
const z = new Array(need + 1).join('0');
if (i < 0) {
c = '-' + z + c.slice(1);
}
else {
c = z + c;
}
}
}
}
N.push(c);
}
return N;
}
function expand_(str, max, maxLength, isTop) {
// Consume the string's top-level brace groups left to right, threading a
// running set of combined prefixes (`acc`). Expanding the tail iteratively -
// rather than recursing on `m.post` once per group - keeps the native stack
// depth constant, so deeply chained input (`'{a,b}'.repeat(3000)`) can no
// longer overflow the stack, and leaves a single accumulator whose size
// `maxLength` bounds directly (CVE-2026-14257).
let acc = [''];
// Bash drops empty results, but only when the *first* top-level group is a
// comma set - a sequence like `{a..\}` may legitimately yield ''. The drop
// is on the final strings, so it is applied to whichever `combine` produces
// them (the one with no brace set left in the tail).
let dropEmpties = false;
let firstGroup = true;
for (;;) {
const m = balanced('{', '}', str);
// No brace set left: the rest of the string is literal.
if (!m) {
return combine(acc, str, [''], max, maxLength, dropEmpties);
}
// no need to expand pre, since it is guaranteed to be free of brace-sets
const pre = m.pre;
if (/\$$/.test(pre)) {
acc = combine(acc, pre + '{' + m.body + '}', [''], max, maxLength, dropEmpties && !m.post.length);
firstGroup = false;
if (!m.post.length)
break;
str = m.post;
continue;
}
const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
const isSequence = isNumericSequence || isAlphaSequence; const isSequence = isNumericSequence || isAlphaSequence;
@@ -30371,87 +30688,47 @@ function expand_(str, max, isTop) {
// {a},b} // {a},b}
if (m.post.match(/,(?!,).*\}/)) { if (m.post.match(/,(?!,).*\}/)) {
str = m.pre + '{' + m.body + escClose + m.post; str = m.pre + '{' + m.body + escClose + m.post;
return expand_(str, max, true); isTop = true;
continue;
} }
return [str]; // Nothing here expands, so the whole remaining string is literal.
return combine(acc, pre + '{' + m.body + '}' + m.post, [''], max, maxLength, dropEmpties);
} }
let n; if (firstGroup) {
dropEmpties = isTop && !isSequence;
firstGroup = false;
}
let values;
if (isSequence) { if (isSequence) {
n = m.body.split(/\.\./); values = expandSequence(m.body, isAlphaSequence, max);
} }
else { else {
n = parseCommaParts(m.body); let n = parseCommaParts(m.body);
if (n.length === 1 && n[0] !== undefined) { if (n.length === 1 && n[0] !== undefined) {
// x{{a,b}}y ==> x{a}y x{b}y // x{{a,b}}y ==> x{a}y x{b}y
n = expand_(n[0], max, false).map(embrace); n = expand_(n[0], max, maxLength, false).map(embrace);
//XXX is this necessary? Can't seem to hit it in tests. //XXX is this necessary? Can't seem to hit it in tests.
/* c8 ignore start */ /* c8 ignore start */
if (n.length === 1) { if (n.length === 1) {
return post.map(p => m.pre + n[0] + p); acc = combine(acc, pre + n[0], [''], max, maxLength, dropEmpties && !m.post.length);
if (!m.post.length)
break;
str = m.post;
continue;
} }
/* c8 ignore stop */ /* c8 ignore stop */
} }
} values = [];
// at this point, n is the parts, and we know it's not a comma set
// with a single entry.
let N;
if (isSequence && n[0] !== undefined && n[1] !== undefined) {
const x = numeric(n[0]);
const y = numeric(n[1]);
const width = Math.max(n[0].length, n[1].length);
let incr = n.length === 3 && n[2] !== undefined ?
Math.max(Math.abs(numeric(n[2])), 1)
: 1;
let test = lte;
const reverse = y < x;
if (reverse) {
incr *= -1;
test = gte;
}
const pad = n.some(isPadded);
N = [];
for (let i = x; test(i, y) && N.length < max; i += incr) {
let c;
if (isAlphaSequence) {
c = String.fromCharCode(i);
if (c === '\\') {
c = '';
}
}
else {
c = String(i);
if (pad) {
const need = width - c.length;
if (need > 0) {
const z = new Array(need + 1).join('0');
if (i < 0) {
c = '-' + z + c.slice(1);
}
else {
c = z + c;
}
}
}
}
N.push(c);
}
}
else {
N = [];
for (let j = 0; j < n.length; j++) { for (let j = 0; j < n.length; j++) {
N.push.apply(N, expand_(n[j], max, false)); values.push.apply(values, expand_(n[j], max, maxLength, false));
}
}
for (let j = 0; j < N.length; j++) {
for (let k = 0; k < post.length && expansions.length < max; k++) {
const expansion = pre + N[j] + post[k];
if (!isTop || isSequence || expansion) {
expansions.push(expansion);
}
} }
} }
acc = combine(acc, pre, values, max, maxLength, dropEmpties && !m.post.length);
if (!m.post.length)
break;
str = m.post;
} }
return expansions; return acc;
} }
const MAX_PATTERN_LENGTH = 1024 * 64; const MAX_PATTERN_LENGTH = 1024 * 64;
@@ -33398,6 +33675,7 @@ class TomlError extends Error {
let INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/; let INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
let FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/; let FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
let LEADING_ZERO = /^[+-]?0[0-9_]/; let LEADING_ZERO = /^[+-]?0[0-9_]/;
/** @internal */
function parseString(str, ptr) { function parseString(str, ptr) {
let c = str[ptr++]; let c = str[ptr++];
let first = c; let first = c;
@@ -33548,6 +33826,7 @@ function parseString(str, ptr) {
} }
throw new TomlError('unfinished string', { toml: str, ptr }); throw new TomlError('unfinished string', { toml: str, ptr });
} }
/** @internal */
function parseValue(value, toml, ptr, integersAsBigInt) { function parseValue(value, toml, ptr, integersAsBigInt) {
// Constant values // Constant values
if (value === 'true') if (value === 'true')
@@ -33629,12 +33908,14 @@ function parseValue(value, toml, ptr, integersAsBigInt) {
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/** @internal */
function indexOfNewline(str, start = 0, end = str.length) { function indexOfNewline(str, start = 0, end = str.length) {
let idx = str.indexOf('\n', start); let idx = str.indexOf('\n', start);
if (str[idx - 1] === '\r') if (str[idx - 1] === '\r')
idx--; idx--;
return idx <= end ? idx : -1; return idx <= end ? idx : -1;
} }
/** @internal */
function skipComment(str, ptr) { function skipComment(str, ptr) {
for (let i = ptr; i < str.length; i++) { for (let i = ptr; i < str.length; i++) {
let c = str[i]; let c = str[i];
@@ -33651,6 +33932,7 @@ function skipComment(str, ptr) {
} }
return str.length; return str.length;
} }
/** @internal */
function skipVoid(str, ptr, banNewLines, banComments) { function skipVoid(str, ptr, banNewLines, banComments) {
let c; let c;
while (1) { while (1) {
@@ -33664,6 +33946,7 @@ function skipVoid(str, ptr, banNewLines, banComments) {
} }
return ptr; return ptr;
} }
/** @internal */
function skipUntil(str, ptr, sep, end, banNewLines = false) { function skipUntil(str, ptr, sep, end, banNewLines = false) {
if (!end) { if (!end) {
ptr = indexOfNewline(str, ptr); ptr = indexOfNewline(str, ptr);
@@ -33673,6 +33956,8 @@ function skipUntil(str, ptr, sep, end, banNewLines = false) {
let c = str[i]; let c = str[i];
if (c === '#') { if (c === '#') {
i = indexOfNewline(str, i); i = indexOfNewline(str, i);
if (i < 0)
break;
} }
else if (c === sep) { else if (c === sep) {
return i + 1; return i + 1;
@@ -33725,6 +34010,7 @@ function sliceAndTrimEndOf(str, startPtr, endPtr) {
} }
return [value.trimEnd(), commentIdx]; return [value.trimEnd(), commentIdx];
} }
/** @internal */
function extractValue(str, ptr, end, depth, integersAsBigInt) { function extractValue(str, ptr, end, depth, integersAsBigInt) {
if (depth === 0) { if (depth === 0) {
throw new TomlError('document contains excessively nested structures. aborting.', { throw new TomlError('document contains excessively nested structures. aborting.', {
@@ -33812,6 +34098,7 @@ function extractValue(str, ptr, end, depth, integersAsBigInt) {
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
let KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/; let KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
/** @internal */
function parseKey(str, ptr, end = '=') { function parseKey(str, ptr, end = '=') {
let dot = ptr - 1; let dot = ptr - 1;
let parsed = []; let parsed = [];
@@ -33878,6 +34165,7 @@ function parseKey(str, ptr, end = '=') {
} while (dot + 1 && dot < endPtr); } while (dot + 1 && dot < endPtr);
return [parsed, skipVoid(str, endPtr + 1, true, true)]; return [parsed, skipVoid(str, endPtr + 1, true, true)];
} }
/** @internal */
function parseInlineTable(str, ptr, depth, integersAsBigInt) { function parseInlineTable(str, ptr, depth, integersAsBigInt) {
let res = {}; let res = {};
let seen = new Set(); let seen = new Set();
@@ -33931,6 +34219,7 @@ function parseInlineTable(str, ptr, depth, integersAsBigInt) {
} }
return [res, ptr]; return [res, ptr];
} }
/** @internal */
function parseArray(str, ptr, depth, integersAsBigInt) { function parseArray(str, ptr, depth, integersAsBigInt) {
let res = []; let res = [];
let c; let c;
@@ -34145,10 +34434,10 @@ async function getCacheProvider() {
let cache; let cache;
switch (cacheProvider) { switch (cacheProvider) {
case "github": case "github":
cache = await import('./cache-oK5XC6-w.js'); cache = await import('./cache-CxTjXol0.js');
break; break;
case "warpbuild": case "warpbuild":
cache = await import('./cache-COXGx-w3.js').then(function (n) { return n.c; }); cache = await import('./cache-DhiwylR9.js').then(function (n) { return n.c; });
break; break;
default: default:
throw new Error(`The \`cache-provider\` \`${cacheProvider}\` is not valid.`); throw new Error(`The \`cache-provider\` \`${cacheProvider}\` is not valid.`);
@@ -34183,7 +34472,7 @@ class Workspace {
debug(`collecting metadata for "${this.root}"`); debug(`collecting metadata for "${this.root}"`);
const meta = JSON.parse(await getCmdOutput(cmdFormat, cmd, { const meta = JSON.parse(await getCmdOutput(cmdFormat, cmd, {
cwd: this.root, cwd: this.root,
env: { ...process.env, "CARGO_ENCODED_RUSTFLAGS": "" }, env: { ...process.env, CARGO_ENCODED_RUSTFLAGS: "" },
})); }));
debug(`workspace "${this.root}" has ${meta.packages.length} packages`); debug(`workspace "${this.root}" has ${meta.packages.length} packages`);
for (const pkg of meta.packages.filter(filter)) { for (const pkg of meta.packages.filter(filter)) {
+1 -1
View File
@@ -1,4 +1,4 @@
import { e as error, g as getCacheProvider, a as getInput, b as exportVariable, C as CacheConfig, i as info, c as cleanTargetDir, r as reportError, s as setOutput } from './cleanup-BnmJoqJp.js'; import { e as error, g as getCacheProvider, a as getInput, b as exportVariable, C as CacheConfig, i as info, c as cleanTargetDir, r as reportError, s as setOutput } from './cleanup-BaSEYL-3.js';
import 'os'; import 'os';
import 'crypto'; import 'crypto';
import 'fs'; import 'fs';
+1 -1
View File
@@ -1,4 +1,4 @@
import { e as error, g as getCacheProvider, a as getInput, d as isCacheUpToDate, i as info, C as CacheConfig, c as cleanTargetDir, f as debug, h as cleanRegistry, j as cleanBin, k as cleanGit, r as reportError, l as exec } from './cleanup-BnmJoqJp.js'; import { e as error, g as getCacheProvider, a as getInput, d as isCacheUpToDate, i as info, C as CacheConfig, c as cleanTargetDir, f as debug, h as cleanRegistry, j as cleanBin, k as cleanGit, r as reportError, l as exec } from './cleanup-BaSEYL-3.js';
import 'os'; import 'os';
import 'crypto'; import 'crypto';
import 'fs'; import 'fs';
+10 -10
View File
@@ -1778,27 +1778,27 @@ function requireDist () {
return dist; return dist;
} }
var state = {}; var stateCjs$1 = {};
var hasRequiredState; var hasRequiredStateCjs$1;
function requireState () { function requireStateCjs$1 () {
if (hasRequiredState) return state; if (hasRequiredStateCjs$1) return stateCjs$1;
hasRequiredState = 1; hasRequiredStateCjs$1 = 1;
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT License. // Licensed under the MIT License.
Object.defineProperty(state, "__esModule", { value: true }); Object.defineProperty(stateCjs$1, "__esModule", { value: true });
state.state = void 0; stateCjs$1.state = void 0;
/** /**
* @internal * @internal
* *
* Holds the singleton instrumenter, to be shared across CJS and ESM imports. * Holds the singleton instrumenter, to be shared across CJS and ESM imports.
*/ */
state.state = { stateCjs$1.state = {
instrumenterImplementation: undefined, instrumenterImplementation: undefined,
}; };
return state; return stateCjs$1;
} }
var stateCjs = {}; var stateCjs = {};
@@ -1822,4 +1822,4 @@ function requireStateCjs () {
return stateCjs; return stateCjs;
} }
export { requireDist as a, requireState as b, requireStateCjs as c, requireSrc as d, requireDist$1 as r }; export { requireDist as a, requireStateCjs$1 as b, requireStateCjs as c, requireSrc as d, requireDist$1 as r };
+555 -176
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -23,13 +23,13 @@
"homepage": "https://github.com/Swatinem/rust-cache#readme", "homepage": "https://github.com/Swatinem/rust-cache#readme",
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@actions/cache": "^6.1.0", "@actions/cache": "^6.2.0",
"@actions/core": "^3.0.1", "@actions/core": "^3.0.1",
"@actions/exec": "^3.0.0", "@actions/exec": "^3.0.0",
"@actions/glob": "^0.7.0", "@actions/glob": "^0.7.0",
"@actions/io": "^3.0.2", "@actions/io": "^3.0.2",
"@actions/warpbuild-cache": "npm:github-actions.warp-cache@1.4.7", "@actions/warpbuild-cache": "npm:github-actions.warp-cache@1.4.7",
"smol-toml": "^1.7.0" "smol-toml": "^1.7.1"
}, },
"overrides": { "overrides": {
"@actions/cache": { "@actions/cache": {
@@ -40,10 +40,10 @@
"@rollup/plugin-commonjs": "^29.0.3", "@rollup/plugin-commonjs": "^29.0.3",
"@rollup/plugin-json": "^6.1.0", "@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^16.0.3", "@rollup/plugin-node-resolve": "^16.0.3",
"@types/node": "^25.9.3", "@types/node": "^26.1.1",
"linefix": "^0.1.1", "linefix": "^0.1.1",
"rollup": "^4.62.2", "rollup": "^4.62.2",
"typescript": "6.0.3" "typescript": "7.0.2"
}, },
"scripts": { "scripts": {
"clean": "node -e \"(async () => { try { await require('fs/promises').rm('dist', { recursive: true }); } catch {} })()\"", "clean": "node -e \"(async () => { try { await require('fs/promises').rm('dist', { recursive: true }); } catch {} })()\"",
+3 -3
View File
@@ -3,9 +3,9 @@ import * as io from "@actions/io";
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import { CARGO_HOME } from "./config"; import { CARGO_HOME } from "./config.js";
import { exists } from "./utils"; import { exists } from "./utils.js";
import { Packages } from "./workspace"; import { Packages } from "./workspace.js";
export async function cleanTargetDir(targetDir: string, packages: Packages, checkTimestamp = false) { export async function cleanTargetDir(targetDir: string, packages: Packages, checkTimestamp = false) {
core.debug(`cleaning target directory "${targetDir}"`); core.debug(`cleaning target directory "${targetDir}"`);
+2 -2
View File
@@ -7,8 +7,8 @@ import os from "os";
import path from "path"; import path from "path";
import * as toml from "smol-toml"; import * as toml from "smol-toml";
import { CacheProvider, exists, getCmdOutput } from "./utils"; import { CacheProvider, exists, getCmdOutput } from "./utils.js";
import { Workspace } from "./workspace"; import { Workspace } from "./workspace.js";
const HOME = os.homedir(); const HOME = os.homedir();
export const CARGO_HOME = process.env.CARGO_HOME || path.join(HOME, ".cargo"); export const CARGO_HOME = process.env.CARGO_HOME || path.join(HOME, ".cargo");
+3 -3
View File
@@ -1,8 +1,8 @@
import * as core from "@actions/core"; import * as core from "@actions/core";
import { cleanTargetDir } from "./cleanup"; import { cleanTargetDir } from "./cleanup.js";
import { CacheConfig } from "./config"; import { CacheConfig } from "./config.js";
import { getCacheProvider, reportError } from "./utils"; import { getCacheProvider, reportError } from "./utils.js";
process.on("uncaughtException", (e) => { process.on("uncaughtException", (e) => {
core.error(e.message); core.error(e.message);
+3 -3
View File
@@ -1,9 +1,9 @@
import * as core from "@actions/core"; import * as core from "@actions/core";
import * as exec from "@actions/exec"; import * as exec from "@actions/exec";
import { cleanBin, cleanGit, cleanRegistry, cleanTargetDir } from "./cleanup"; import { cleanBin, cleanGit, cleanRegistry, cleanTargetDir } from "./cleanup.js";
import { CacheConfig, isCacheUpToDate } from "./config"; import { CacheConfig, isCacheUpToDate } from "./config.js";
import { getCacheProvider, reportError } from "./utils"; import { getCacheProvider, reportError } from "./utils.js";
process.on("uncaughtException", (e) => { process.on("uncaughtException", (e) => {
core.error(e.message); core.error(e.message);
+11 -4
View File
@@ -1,14 +1,21 @@
import * as core from "@actions/core"; import * as core from "@actions/core";
import path from "path"; import path from "path";
import { getCmdOutput } from "./utils"; import { getCmdOutput } from "./utils.js";
const SAVE_TARGETS = new Set(["lib", "cdylib", "dylib", "rlib", "staticlib", "proc-macro"]); const SAVE_TARGETS = new Set(["lib", "cdylib", "dylib", "rlib", "staticlib", "proc-macro"]);
export class Workspace { export class Workspace {
constructor(public root: string, public target: string) {} constructor(
public root: string,
public target: string,
) {}
async getPackages(cmdFormat: string, filter: (p: Meta["packages"][0]) => boolean, extraArgs?: string): Promise<Packages> { async getPackages(
cmdFormat: string,
filter: (p: Meta["packages"][0]) => boolean,
extraArgs?: string,
): Promise<Packages> {
const cmd = "cargo metadata --all-features --format-version 1" + (extraArgs ? ` ${extraArgs}` : ""); const cmd = "cargo metadata --all-features --format-version 1" + (extraArgs ? ` ${extraArgs}` : "");
let packages: Packages = []; let packages: Packages = [];
try { try {
@@ -16,7 +23,7 @@ export class Workspace {
const meta: Meta = JSON.parse( const meta: Meta = JSON.parse(
await getCmdOutput(cmdFormat, cmd, { await getCmdOutput(cmdFormat, cmd, {
cwd: this.root, cwd: this.root,
env: { ...process.env, "CARGO_ENCODED_RUSTFLAGS": "" }, env: { ...process.env, CARGO_ENCODED_RUSTFLAGS: "" },
}), }),
); );
core.debug(`workspace "${this.root}" has ${meta.packages.length} packages`); core.debug(`workspace "${this.root}" has ${meta.packages.length} packages`);
-3
View File
@@ -8,9 +8,6 @@
"target": "es2024", "target": "es2024",
"resolveJsonModule": true, "resolveJsonModule": true,
"ignoreDeprecations": "6.0",
"moduleResolution": "node",
"module": "esnext",
"esModuleInterop": true, "esModuleInterop": true,
"incremental": true, "incremental": true,