Skip to content

chore(deps): update golangci/golangci-lint-action action to v9.3.0 - #367

Merged
jwadolowski merged 1 commit into
masterfrom
renovate/golangci-golangci-lint-action-9-x
Jul 21, 2026
Merged

chore(deps): update golangci/golangci-lint-action action to v9.3.0#367
jwadolowski merged 1 commit into
masterfrom
renovate/golangci-golangci-lint-action-9-x

Conversation

@renovate

@renovate renovate Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Type Update Change
golangci/golangci-lint-action action minor v9.2.1v9.3.0

Release Notes

golangci/golangci-lint-action (golangci/golangci-lint-action)

v9.3.0

Compare Source

What's Changed

Changes
Dependencies

Full Changelog: golangci/golangci-lint-action@v9.2.1...v9.3.0


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate
renovate Bot requested review from jwadolowski and mschfh as code owners July 21, 2026 15:28
@github-actions

Copy link
Copy Markdown

[puLL-Merge] - golangci/golangci-lint-action@v9.2.1..v9.3.0

Diff
diff --git .github/workflows/codeql.yaml .github/workflows/codeql.yaml
index d3c8d2de5d..594321e239 100644
--- .github/workflows/codeql.yaml
+++ .github/workflows/codeql.yaml
@@ -35,7 +35,7 @@ jobs:
 
       # Initializes the CodeQL tools for scanning.
       - name: Initialize CodeQL
-        uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
+        uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
         # Override language selection by uncommenting this and choosing your languages
         with:
           languages: 'javascript-typescript'
@@ -45,4 +45,4 @@ jobs:
           npm run all
 
       - name: Perform CodeQL Analysis
-        uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
+        uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
diff --git README.md README.md
index 0b18ece950..c487872fe6 100644
--- README.md
+++ README.md
@@ -616,6 +616,23 @@ with:
 
 </details>
 
+#### `no-run-logs-group`
+
+(optional)
+
+This option disables the grouping of logs from golangci-lint run.
+
+<details>
+<summary>Example</summary>
+
+```yaml
+uses: golangci/golangci-lint-action@v9
+with:
+  experimental: "no-run-logs-group"
+```
+
+</details>
+
 ## Annotations
 
 Currently, GitHub parses the action's output and creates [annotations](https://github.blog/2018-12-14-introducing-check-runs-and-annotations/).
diff --git action.yml action.yml
index 48e8c9bc30..283e626dba 100644
--- action.yml
+++ action.yml
@@ -76,6 +76,7 @@ inputs:
     description: |
       Experimental options for the action.
       List of comma separated options.
+      Available options: `automatic-module-directories`, `no-run-logs-group`
     default: ""
     required: false
 runs:
diff --git dist/post_run/index.js dist/post_run/index.js
index 28547fb706..997d59a46e 100644
--- dist/post_run/index.js
+++ dist/post_run/index.js
@@ -29642,6 +29642,29 @@ function _generateTmpName(opts) {
   return path.join(tmpDir, opts.dir, name);
 }
 
+/**
+ * Check the prefix, postfix, and template options.
+ *
+ * Rejects non-string inputs so that a non-string `.includes('..')` cannot evade
+ * the substring check (e.g. an Array whose `.includes('..')` is element-wise,
+ * or a duck-typed object with a custom `.includes`), and so that the value is
+ * not later coerced to a string with traversal sequences via `Array.prototype.join`
+ * or `path.join`.
+ *
+ * @private
+ */
+function _assertPath(option, value) {
+  if (typeof value !== 'string') {
+    throw new Error(`${option} option must be a string, got "${typeof value}".`);
+  }
+
+  if (value.includes("..")) {
+    throw new Error("Relative value not allowed");
+  }
+
+  return value;
+}
+
 /**
  * Asserts and sanitizes the basic options.
  *
@@ -29656,13 +29679,19 @@ function _assertOptionsBase(options) {
 
     // must not fail on valid .<name> or ..<name> or similar such constructs
     const basename = path.basename(name);
-    if (basename === '..' || basename === '.' || basename !== name)
+    if (basename === '..' || basename === '.' || basename !== name) {
       throw new Error(`name option must not contain a path, found "${name}".`);
+    }
   }
 
   /* istanbul ignore else */
-  if (!_isUndefined(options.template) && !options.template.match(TEMPLATE_PATTERN)) {
-    throw new Error(`Invalid template, found "${options.template}".`);
+  if (!_isUndefined(options.template)) {
+    if (typeof options.template !== 'string') {
+      throw new Error(`template option must be a string, got "${typeof options.template}".`);
+    }
+    if (!options.template.match(TEMPLATE_PATTERN)) {
+      throw new Error(`Invalid template, found "${options.template}".`);
+    }
   }
 
   /* istanbul ignore else */
@@ -29678,8 +29707,9 @@ function _assertOptionsBase(options) {
   options.unsafeCleanup = !!options.unsafeCleanup;
 
   // for completeness' sake only, also keep (multiple) blanks if the user, purportedly sane, requests us to
-  options.prefix = _isUndefined(options.prefix) ? '' : options.prefix;
-  options.postfix = _isUndefined(options.postfix) ? '' : options.postfix;
+  options.prefix = _isUndefined(options.prefix) ? '' : _assertPath('prefix', options.prefix);
+  options.postfix = _isUndefined(options.postfix) ? '' : _assertPath('postfix', options.postfix);
+  options.template = _isUndefined(options.template) ? undefined : _assertPath('template', options.template);
 }
 
 /**
@@ -29695,7 +29725,7 @@ function _getRelativePath(option, name, tmpDir, cb) {
 
     const relativePath = path.relative(tmpDir, resolvedPath);
 
-    if (!resolvedPath.startsWith(tmpDir)) {
+    if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
       return cb(new Error(`${option} option must be relative to "${tmpDir}", found "${relativePath}".`));
     }
 
@@ -29714,7 +29744,7 @@ function _getRelativePathSync(option, name, tmpDir) {
   const resolvedPath = _resolvePathSync(name, tmpDir);
   const relativePath = path.relative(tmpDir, resolvedPath);
 
-  if (!resolvedPath.startsWith(tmpDir)) {
+  if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
     throw new Error(`${option} option must be relative to "${tmpDir}", found "${relativePath}".`);
   }
 
@@ -34810,7 +34840,6 @@ function defaultFactory (origin, opts) {
 
 class Agent extends DispatcherBase {
   constructor ({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) {
-
     if (typeof factory !== 'function') {
       throw new InvalidArgumentError('factory must be a function.')
     }
@@ -35198,6 +35227,9 @@ const EMPTY_BUF = Buffer.alloc(0)
 const FastBuffer = Buffer[Symbol.species]
 const addListener = util.addListener
 const removeAllListeners = util.removeAllListeners
+const kIdleSocketValidation = Symbol('kIdleSocketValidation')
+const kIdleSocketValidationTimeout = Symbol('kIdleSocketValidationTimeout')
+const kSocketUsed = Symbol('kSocketUsed')
 
 let extractBody
 
@@ -35420,29 +35452,71 @@ class Parser {
 
       const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr
 
-      if (ret === constants.ERROR.PAUSED_UPGRADE) {
-        this.onUpgrade(data.slice(offset))
-      } else if (ret === constants.ERROR.PAUSED) {
-        this.paused = true
-        socket.unshift(data.slice(offset))
-      } else if (ret !== constants.ERROR.OK) {
-        const ptr = llhttp.llhttp_get_error_reason(this.ptr)
-        let message = ''
-        /* istanbul ignore else: difficult to make a test case for */
-        if (ptr) {
-          const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0)
-          message =
-            'Response does not match the HTTP/1.1 protocol (' +
-            Buffer.from(llhttp.memory.buffer, ptr, len).toString() +
-            ')'
-        }
-        throw new HTTPParserError(message, constants.ERROR[ret], data.slice(offset))
+      if (ret !== constants.ERROR.OK) {
+        const body = data.subarray(offset)
+
+        if (ret === constants.ERROR.PAUSED_UPGRADE) {
+          this.onUpgrade(body)
+        } else if (ret === constants.ERROR.PAUSED) {
+          this.paused = true
+          socket.unshift(body)
+        } else {
+          throw this.createError(ret, body)
+        }
       }
     } catch (err) {
       util.destroy(socket, err)
     }
   }
 
+  finish () {
+    assert(currentParser === null)
+    assert(this.ptr != null)
+    assert(!this.paused)
+
+    const { llhttp } = this
+
+    let ret
+
+    try {
+      currentParser = this
+      ret = llhttp.llhttp_finish(this.ptr)
+    } finally {
+      currentParser = null
+    }
+
+    if (ret === constants.ERROR.OK) {
+      return null
+    }
+
+    if (ret === constants.ERROR.PAUSED || ret === constants.ERROR.PAUSED_UPGRADE) {
+      this.paused = true
+      return null
+    }
+
+    return this.createError(ret, EMPTY_BUF)
+  }
+
+  createError (ret, data) {
+    const { llhttp, contentLength, bytesRead } = this
+
+    if (contentLength && bytesRead !== parseInt(contentLength, 10)) {
+      return new ResponseContentLengthMismatchError()
+    }
+
+    const ptr = llhttp.llhttp_get_error_reason(this.ptr)
+    let message = ''
+    if (ptr) {
+      const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0)
+      message =
+        'Response does not match the HTTP/1.1 protocol (' +
+        Buffer.from(llhttp.memory.buffer, ptr, len).toString() +
+        ')'
+    }
+
+    return new HTTPParserError(message, constants.ERROR[ret], data)
+  }
+
   destroy () {
     assert(this.ptr != null)
     assert(currentParser == null)
@@ -35470,6 +35544,11 @@ class Parser {
       return -1
     }
 
+    if (client[kRunning] === 0) {
+      util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket)))
+      return -1
+    }
+
     const request = client[kQueue][client[kRunningIdx]]
     if (!request) {
       return -1
@@ -35573,6 +35652,11 @@ class Parser {
       return -1
     }
 
+    if (client[kRunning] === 0) {
+      util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket)))
+      return -1
+    }
+
     const request = client[kQueue][client[kRunningIdx]]
 
     /* istanbul ignore next: difficult to make a test case for */
@@ -35746,6 +35830,7 @@ class Parser {
     request.onComplete(headers)
 
     client[kQueue][client[kRunningIdx]++] = null
+    socket[kSocketUsed] = true
 
     if (socket[kWriting]) {
       assert(client[kRunning] === 0)
@@ -35804,6 +35889,9 @@ async function connectH1 (client, socket) {
   socket[kWriting] = false
   socket[kReset] = false
   socket[kBlocking] = false
+  socket[kIdleSocketValidation] = 0
+  socket[kIdleSocketValidationTimeout] = null
+  socket[kSocketUsed] = false
   socket[kParser] = new Parser(client, socket, llhttpInstance)
 
   addListener(socket, 'error', function (err) {
@@ -35814,8 +35902,11 @@ async function connectH1 (client, socket) {
     // On Mac OS, we get an ECONNRESET even if there is a full body to be forwarded
     // to the user.
     if (err.code === 'ECONNRESET' && parser.statusCode && !parser.shouldKeepAlive) {
-      // We treat all incoming data so for as a valid response.
-      parser.onMessageComplete()
+      const parserErr = parser.finish()
+      if (parserErr) {
+        this[kError] = parserErr
+        this[kClient][kOnError](parserErr)
+      }
       return
     }
 
@@ -35834,8 +35925,10 @@ async function connectH1 (client, socket) {
     const parser = this[kParser]
 
     if (parser.statusCode && !parser.shouldKeepAlive) {
-      // We treat all incoming data so far as a valid response.
-      parser.onMessageComplete()
+      const parserErr = parser.finish()
+      if (parserErr) {
+        util.destroy(this, parserErr)
+      }
       return
     }
 
@@ -35845,10 +35938,11 @@ async function connectH1 (client, socket) {
     const client = this[kClient]
     const parser = this[kParser]
 
+    clearIdleSocketValidation(this)
+
     if (parser) {
       if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) {
-        // We treat all incoming data so far as a valid response.
-        parser.onMessageComplete()
+        this[kError] = parser.finish() || this[kError]
       }
 
       this[kParser].destroy()
@@ -35911,7 +36005,7 @@ async function connectH1 (client, socket) {
       return socket.destroyed
     },
     busy (request) {
-      if (socket[kWriting] || socket[kReset] || socket[kBlocking]) {
+      if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) {
         return true
       }
 
@@ -35949,6 +36043,31 @@ async function connectH1 (client, socket) {
   }
 }
 
+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) {
   const socket = client[kSocket]
 
@@ -35963,6 +36082,32 @@ function resumeH1 (client) {
       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 (socket[kParser].timeoutType !== TIMEOUT_KEEP_ALIVE) {
         socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_KEEP_ALIVE)
@@ -36056,6 +36201,7 @@ function writeH1 (client, request) {
   }
 
   const socket = client[kSocket]
+  clearIdleSocketValidation(socket)
 
   const abort = (err) => {
     if (request.aborted || request.completed) {
@@ -37928,6 +38074,7 @@ class DispatcherBase extends Dispatcher {
 
   get webSocketOptions () {
     return {
+      maxFragments: this[kWebSocketOptions].maxFragments ?? 131072,
       maxPayloadSize: this[kWebSocketOptions].maxPayloadSize ?? 128 * 1024 * 1024
     }
   }
@@ -43864,32 +44011,25 @@ function parseUnparsedAttributes (unparsedAttributes, cookieAttributeList = {})
     // If the attribute-name case-insensitively matches the string
     // "SameSite", the user agent MUST process the cookie-av as follows:
 
-    // 1. Let enforcement be "Default".
-    let enforcement = 'Default'
-
     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
-    //    "Strict", set enforcement to "Strict".
-    if (attributeValueLowercase.includes('strict')) {
-      enforcement = 'Strict'
+    // 1. If cookie-av's attribute-value is a case-insensitive match for
+    //    "None", append an attribute to the cookie-attribute-list with an
+    //    attribute-name of "SameSite" and an attribute-value of "None".
+    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 {
     cookieAttributeList.unparsed ??= []
 
@@ -56715,6 +56855,11 @@ const { closeWebSocketConnection } = __nccwpck_require__(86897)
 const { PerMessageDeflate } = __nccwpck_require__(19469)
 const { MessageSizeExceededError } = __nccwpck_require__(68707)
 
+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.
 // Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
 // Copyright (c) 2013 Arnout Kazemier and contributors
@@ -56734,19 +56879,23 @@ class ByteParser extends Writable {
   /** @type {Map<string, PerMessageDeflate>} */
   #extensions
 
+  /** @type {number} */
+  #maxFragments
+
   /** @type {number} */
   #maxPayloadSize
 
   /**
    * @param {import('./websocket').WebSocket} ws
    * @param {Map<string, string>|null} extensions
-   * @param {{ maxPayloadSize?: number }} [options]
+   * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options]
    */
   constructor (ws, extensions, options = {}) {
     super()
 
     this.ws = ws
     this.#extensions = extensions == null ? new Map() : extensions
+    this.#maxFragments = options.maxFragments ?? 0
     this.#maxPayloadSize = options.maxPayloadSize ?? 0
 
     if (this.#extensions.has('permessage-deflate')) {
@@ -56770,9 +56919,9 @@ class ByteParser extends Writable {
     if (
       this.#maxPayloadSize > 0 &&
       !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
     }
 
@@ -56937,10 +57086,12 @@ class ByteParser extends Writable {
           this.#state = parserStates.INFO
         } else {
           if (!this.#info.compressed) {
-            this.writeFragments(body)
+            if (!this.writeFragments(body)) {
+              return
+            }
 
             if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
-              failWebsocketConnection(this.ws, new MessageSizeExceededError().message)
+              failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message)
               return
             }
 
@@ -56959,14 +57110,17 @@ class ByteParser extends Writable {
               this.#info.fin,
               (error, data) => {
                 if (error) {
-                  failWebsocketConnection(this.ws, error.message)
+                  const code = error instanceof MessageSizeExceededError ? 1009 : 1007
+                  failWebsocketConnectionWithCode(this.ws, code, error.message)
                   return
                 }
 
-                this.writeFragments(data)
+                if (!this.writeFragments(data)) {
+                  return
+                }
 
                 if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
-                  failWebsocketConnection(this.ws, new MessageSizeExceededError().message)
+                  failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message)
                   return
                 }
 
@@ -57036,8 +57190,17 @@ class ByteParser extends Writable {
   }
 
   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.#fragments.push(fragment)
+    return true
   }
 
   consumeFragments () {
@@ -58090,9 +58253,12 @@ class WebSocket extends EventTarget {
     // once this happens, the connection is open
     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, {
+      maxFragments,
       maxPayloadSize
     })
     parser.on('drain', onParserDrain)
@@ -59301,15 +59467,23 @@ function modulesAutoDetection(rootDir) {
 async function runLint(binPath) {
     const workingDirectory = getWorkingDirectory();
     const experimental = core.getInput(`experimental`).split(`,`);
+    const noGroup = experimental.includes(`no-run-logs-group`);
     if (experimental.includes(`automatic-module-directories`)) {
         const wds = modulesAutoDetection(workingDirectory);
         const cwd = process.cwd();
         for (const wd of wds) {
-            await core.group(`run golangci-lint in ${path.relative(cwd, wd)}`, () => runGolangciLint(binPath, wd));
+            await optionalGroup(noGroup, `run golangci-lint in ${path.relative(cwd, wd)}`, () => runGolangciLint(binPath, wd));
         }
         return;
     }
-    await core.group(`run golangci-lint`, () => runGolangciLint(binPath, workingDirectory));
+    await optionalGroup(noGroup, `run golangci-lint`, () => runGolangciLint(binPath, workingDirectory));
+}
+async function optionalGroup(noGroup, name, fn) {
+    if (noGroup) {
+        core.info(name);
+        return fn();
+    }
+    return core.group(name, fn);
 }
 async function run() {
     try {
diff --git dist/run/index.js dist/run/index.js
index cfaeba7952..318d9a3dd4 100644
--- dist/run/index.js
+++ dist/run/index.js
@@ -29642,6 +29642,29 @@ function _generateTmpName(opts) {
   return path.join(tmpDir, opts.dir, name);
 }
 
+/**
+ * Check the prefix, postfix, and template options.
+ *
+ * Rejects non-string inputs so that a non-string `.includes('..')` cannot evade
+ * the substring check (e.g. an Array whose `.includes('..')` is element-wise,
+ * or a duck-typed object with a custom `.includes`), and so that the value is
+ * not later coerced to a string with traversal sequences via `Array.prototype.join`
+ * or `path.join`.
+ *
+ * @private
+ */
+function _assertPath(option, value) {
+  if (typeof value !== 'string') {
+    throw new Error(`${option} option must be a string, got "${typeof value}".`);
+  }
+
+  if (value.includes("..")) {
+    throw new Error("Relative value not allowed");
+  }
+
+  return value;
+}
+
 /**
  * Asserts and sanitizes the basic options.
  *
@@ -29656,13 +29679,19 @@ function _assertOptionsBase(options) {
 
     // must not fail on valid .<name> or ..<name> or similar such constructs
     const basename = path.basename(name);
-    if (basename === '..' || basename === '.' || basename !== name)
+    if (basename === '..' || basename === '.' || basename !== name) {
       throw new Error(`name option must not contain a path, found "${name}".`);
+    }
   }
 
   /* istanbul ignore else */
-  if (!_isUndefined(options.template) && !options.template.match(TEMPLATE_PATTERN)) {
-    throw new Error(`Invalid template, found "${options.template}".`);
+  if (!_isUndefined(options.template)) {
+    if (typeof options.template !== 'string') {
+      throw new Error(`template option must be a string, got "${typeof options.template}".`);
+    }
+    if (!options.template.match(TEMPLATE_PATTERN)) {
+      throw new Error(`Invalid template, found "${options.template}".`);
+    }
   }
 
   /* istanbul ignore else */
@@ -29678,8 +29707,9 @@ function _assertOptionsBase(options) {
   options.unsafeCleanup = !!options.unsafeCleanup;
 
   // for completeness' sake only, also keep (multiple) blanks if the user, purportedly sane, requests us to
-  options.prefix = _isUndefined(options.prefix) ? '' : options.prefix;
-  options.postfix = _isUndefined(options.postfix) ? '' : options.postfix;
+  options.prefix = _isUndefined(options.prefix) ? '' : _assertPath('prefix', options.prefix);
+  options.postfix = _isUndefined(options.postfix) ? '' : _assertPath('postfix', options.postfix);
+  options.template = _isUndefined(options.template) ? undefined : _assertPath('template', options.template);
 }
 
 /**
@@ -29695,7 +29725,7 @@ function _getRelativePath(option, name, tmpDir, cb) {
 
     const relativePath = path.relative(tmpDir, resolvedPath);
 
-    if (!resolvedPath.startsWith(tmpDir)) {
+    if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
       return cb(new Error(`${option} option must be relative to "${tmpDir}", found "${relativePath}".`));
     }
 
@@ -29714,7 +29744,7 @@ function _getRelativePathSync(option, name, tmpDir) {
   const resolvedPath = _resolvePathSync(name, tmpDir);
   const relativePath = path.relative(tmpDir, resolvedPath);
 
-  if (!resolvedPath.startsWith(tmpDir)) {
+  if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
     throw new Error(`${option} option must be relative to "${tmpDir}", found "${relativePath}".`);
   }
 
@@ -34810,7 +34840,6 @@ function defaultFactory (origin, opts) {
 
 class Agent extends DispatcherBase {
   constructor ({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) {
-
     if (typeof factory !== 'function') {
       throw new InvalidArgumentError('factory must be a function.')
     }
@@ -35198,6 +35227,9 @@ const EMPTY_BUF = Buffer.alloc(0)
 const FastBuffer = Buffer[Symbol.species]
 const addListener = util.addListener
 const removeAllListeners = util.removeAllListeners
+const kIdleSocketValidation = Symbol('kIdleSocketValidation')
+const kIdleSocketValidationTimeout = Symbol('kIdleSocketValidationTimeout')
+const kSocketUsed = Symbol('kSocketUsed')
 
 let extractBody
 
@@ -35420,29 +35452,71 @@ class Parser {
 
       const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr
 
-      if (ret === constants.ERROR.PAUSED_UPGRADE) {
-        this.onUpgrade(data.slice(offset))
-      } else if (ret === constants.ERROR.PAUSED) {
-        this.paused = true
-        socket.unshift(data.slice(offset))
-      } else if (ret !== constants.ERROR.OK) {
-        const ptr = llhttp.llhttp_get_error_reason(this.ptr)
-        let message = ''
-        /* istanbul ignore else: difficult to make a test case for */
-        if (ptr) {
-          const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0)
-          message =
-            'Response does not match the HTTP/1.1 protocol (' +
-            Buffer.from(llhttp.memory.buffer, ptr, len).toString() +
-            ')'
-        }
-        throw new HTTPParserError(message, constants.ERROR[ret], data.slice(offset))
+      if (ret !== constants.ERROR.OK) {
+        const body = data.subarray(offset)
+
+        if (ret === constants.ERROR.PAUSED_UPGRADE) {
+          this.onUpgrade(body)
+        } else if (ret === constants.ERROR.PAUSED) {
+          this.paused = true
+          socket.unshift(body)
+        } else {
+          throw this.createError(ret, body)
+        }
       }
     } catch (err) {
       util.destroy(socket, err)
     }
   }
 
+  finish () {
+    assert(currentParser === null)
+    assert(this.ptr != null)
+    assert(!this.paused)
+
+    const { llhttp } = this
+
+    let ret
+
+    try {
+      currentParser = this
+      ret = llhttp.llhttp_finish(this.ptr)
+    } finally {
+      currentParser = null
+    }
+
+    if (ret === constants.ERROR.OK) {
+      return null
+    }
+
+    if (ret === constants.ERROR.PAUSED || ret === constants.ERROR.PAUSED_UPGRADE) {
+      this.paused = true
+      return null
+    }
+
+    return this.createError(ret, EMPTY_BUF)
+  }
+
+  createError (ret, data) {
+    const { llhttp, contentLength, bytesRead } = this
+
+    if (contentLength && bytesRead !== parseInt(contentLength, 10)) {
+      return new ResponseContentLengthMismatchError()
+    }
+
+    const ptr = llhttp.llhttp_get_error_reason(this.ptr)
+    let message = ''
+    if (ptr) {
+      const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0)
+      message =
+        'Response does not match the HTTP/1.1 protocol (' +
+        Buffer.from(llhttp.memory.buffer, ptr, len).toString() +
+        ')'
+    }
+
+    return new HTTPParserError(message, constants.ERROR[ret], data)
+  }
+
   destroy () {
     assert(this.ptr != null)
     assert(currentParser == null)
@@ -35470,6 +35544,11 @@ class Parser {
       return -1
     }
 
+    if (client[kRunning] === 0) {
+      util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket)))
+      return -1
+    }
+
     const request = client[kQueue][client[kRunningIdx]]
     if (!request) {
       return -1
@@ -35573,6 +35652,11 @@ class Parser {
       return -1
     }
 
+    if (client[kRunning] === 0) {
+      util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket)))
+      return -1
+    }
+
     const request = client[kQueue][client[kRunningIdx]]
 
     /* istanbul ignore next: difficult to make a test case for */
@@ -35746,6 +35830,7 @@ class Parser {
     request.onComplete(headers)
 
     client[kQueue][client[kRunningIdx]++] = null
+    socket[kSocketUsed] = true
 
     if (socket[kWriting]) {
       assert(client[kRunning] === 0)
@@ -35804,6 +35889,9 @@ async function connectH1 (client, socket) {
   socket[kWriting] = false
   socket[kReset] = false
   socket[kBlocking] = false
+  socket[kIdleSocketValidation] = 0
+  socket[kIdleSocketValidationTimeout] = null
+  socket[kSocketUsed] = false
   socket[kParser] = new Parser(client, socket, llhttpInstance)
 
   addListener(socket, 'error', function (err) {
@@ -35814,8 +35902,11 @@ async function connectH1 (client, socket) {
     // On Mac OS, we get an ECONNRESET even if there is a full body to be forwarded
     // to the user.
     if (err.code === 'ECONNRESET' && parser.statusCode && !parser.shouldKeepAlive) {
-      // We treat all incoming data so for as a valid response.
-      parser.onMessageComplete()
+      const parserErr = parser.finish()
+      if (parserErr) {
+        this[kError] = parserErr
+        this[kClient][kOnError](parserErr)
+      }
       return
     }
 
@@ -35834,8 +35925,10 @@ async function connectH1 (client, socket) {
     const parser = this[kParser]
 
     if (parser.statusCode && !parser.shouldKeepAlive) {
-      // We treat all incoming data so far as a valid response.
-      parser.onMessageComplete()
+      const parserErr = parser.finish()
+      if (parserErr) {
+        util.destroy(this, parserErr)
+      }
       return
     }
 
@@ -35845,10 +35938,11 @@ async function connectH1 (client, socket) {
     const client = this[kClient]
     const parser = this[kParser]
 
+    clearIdleSocketValidation(this)
+
     if (parser) {
       if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) {
-        // We treat all incoming data so far as a valid response.
-        parser.onMessageComplete()
+        this[kError] = parser.finish() || this[kError]
       }
 
       this[kParser].destroy()
@@ -35911,7 +36005,7 @@ async function connectH1 (client, socket) {
       return socket.destroyed
     },
     busy (request) {
-      if (socket[kWriting] || socket[kReset] || socket[kBlocking]) {
+      if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) {
         return true
       }
 
@@ -35949,6 +36043,31 @@ async function connectH1 (client, socket) {
   }
 }
 
+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) {
   const socket = client[kSocket]
 
@@ -35963,6 +36082,32 @@ function resumeH1 (client) {
       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 (socket[kParser].timeoutType !== TIMEOUT_KEEP_ALIVE) {
         socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_KEEP_ALIVE)
@@ -36056,6 +36201,7 @@ function writeH1 (client, request) {
   }
 
   const socket = client[kSocket]
+  clearIdleSocketValidation(socket)
 
   const abort = (err) => {
     if (request.aborted || request.completed) {
@@ -37928,6 +38074,7 @@ class DispatcherBase extends Dispatcher {
 
   get webSocketOptions () {
     return {
+      maxFragments: this[kWebSocketOptions].maxFragments ?? 131072,
       maxPayloadSize: this[kWebSocketOptions].maxPayloadSize ?? 128 * 1024 * 1024
     }
   }
@@ -43864,32 +44011,25 @@ function parseUnparsedAttributes (unparsedAttributes, cookieAttributeList = {})
     // If the attribute-name case-insensitively matches the string
     // "SameSite", the user agent MUST process the cookie-av as follows:
 
-    // 1. Let enforcement be "Default".
-    let enforcement = 'Default'
-
     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
-    //    "Strict", set enforcement to "Strict".
-    if (attributeValueLowercase.includes('strict')) {
-      enforcement = 'Strict'
+    // 1. If cookie-av's attribute-value is a case-insensitive match for
+    //    "None", append an attribute to the cookie-attribute-list with an
+    //    attribute-name of "SameSite" and an attribute-value of "None".
+    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 {
     cookieAttributeList.unparsed ??= []
 
@@ -56715,6 +56855,11 @@ const { closeWebSocketConnection } = __nccwpck_require__(86897)
 const { PerMessageDeflate } = __nccwpck_require__(19469)
 const { MessageSizeExceededError } = __nccwpck_require__(68707)
 
+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.
 // Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
 // Copyright (c) 2013 Arnout Kazemier and contributors
@@ -56734,19 +56879,23 @@ class ByteParser extends Writable {
   /** @type {Map<string, PerMessageDeflate>} */
   #extensions
 
+  /** @type {number} */
+  #maxFragments
+
   /** @type {number} */
   #maxPayloadSize
 
   /**
    * @param {import('./websocket').WebSocket} ws
    * @param {Map<string, string>|null} extensions
-   * @param {{ maxPayloadSize?: number }} [options]
+   * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options]
    */
   constructor (ws, extensions, options = {}) {
     super()
 
     this.ws = ws
     this.#extensions = extensions == null ? new Map() : extensions
+    this.#maxFragments = options.maxFragments ?? 0
     this.#maxPayloadSize = options.maxPayloadSize ?? 0
 
     if (this.#extensions.has('permessage-deflate')) {
@@ -56770,9 +56919,9 @@ class ByteParser extends Writable {
     if (
       this.#maxPayloadSize > 0 &&
       !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
     }
 
@@ -56937,10 +57086,12 @@ class ByteParser extends Writable {
           this.#state = parserStates.INFO
         } else {
           if (!this.#info.compressed) {
-            this.writeFragments(body)
+            if (!this.writeFragments(body)) {
+              return
+            }
 
             if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
-              failWebsocketConnection(this.ws, new MessageSizeExceededError().message)
+              failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message)
               return
             }
 
@@ -56959,14 +57110,17 @@ class ByteParser extends Writable {
               this.#info.fin,
               (error, data) => {
                 if (error) {
-                  failWebsocketConnection(this.ws, error.message)
+                  const code = error instanceof MessageSizeExceededError ? 1009 : 1007
+                  failWebsocketConnectionWithCode(this.ws, code, error.message)
                   return
                 }
 
-                this.writeFragments(data)
+                if (!this.writeFragments(data)) {
+                  return
+                }
 
                 if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
-                  failWebsocketConnection(this.ws, new MessageSizeExceededError().message)
+                  failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message)
                   return
                 }
 
@@ -57036,8 +57190,17 @@ class ByteParser extends Writable {
   }
 
   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.#fragments.push(fragment)
+    return true
   }
 
   consumeFragments () {
@@ -58090,9 +58253,12 @@ class WebSocket extends EventTarget {
     // once this happens, the connection is open
     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, {
+      maxFragments,
       maxPayloadSize
     })
     parser.on('drain', onParserDrain)
@@ -59301,15 +59467,23 @@ function modulesAutoDetection(rootDir) {
 async function runLint(binPath) {
     const workingDirectory = getWorkingDirectory();
     const experimental = core.getInput(`experimental`).split(`,`);
+    const noGroup = experimental.includes(`no-run-logs-group`);
     if (experimental.includes(`automatic-module-directories`)) {
         const wds = modulesAutoDetection(workingDirectory);
         const cwd = process.cwd();
         for (const wd of wds) {
-            await core.group(`run golangci-lint in ${path.relative(cwd, wd)}`, () => runGolangciLint(binPath, wd));
+            await optionalGroup(noGroup, `run golangci-lint in ${path.relative(cwd, wd)}`, () => runGolangciLint(binPath, wd));
         }
         return;
     }
-    await core.group(`run golangci-lint`, () => runGolangciLint(binPath, workingDirectory));
+    await optionalGroup(noGroup, `run golangci-lint`, () => runGolangciLint(binPath, workingDirectory));
+}
+async function optionalGroup(noGroup, name, fn) {
+    if (noGroup) {
+        core.info(name);
+        return fn();
+    }
+    return core.group(name, fn);
 }
 async function run() {
     try {
diff --git package.json package.json
index 5f8a8a228f..d82096b761 100644
--- package.json
+++ package.json
@@ -1,6 +1,6 @@
 {
   "name": "golanci-lint-action",
-  "version": "9.2.1",
+  "version": "9.3.0",
   "private": true,
   "description": "golangci-lint github action",
   "main": "dist/main.js",
@@ -38,7 +38,7 @@
     "@types/semver": "^7.7.1",
     "@types/tmp": "^0.2.6",
     "@types/which": "^3.0.4",
-    "tmp": "^0.2.5",
+    "tmp": "^0.2.7",
     "which": "^7.0.0",
     "yaml": "^2.9.0"
   },
@@ -59,6 +59,6 @@
     "typescript": "^5.9.3"
   },
   "overrides": {
-    "undici": "^6.24.0"
+    "undici": "^6.27.0"
   }
 }
diff --git src/run.ts src/run.ts
index 7faeafb5d1..031bdf40f1 100644
--- src/run.ts
+++ src/run.ts
@@ -205,19 +205,31 @@ async function runLint(binPath: string): Promise<void> {
 
   const experimental = core.getInput(`experimental`).split(`,`)
 
+  const noGroup = experimental.includes(`no-run-logs-group`)
+
   if (experimental.includes(`automatic-module-directories`)) {
     const wds = modulesAutoDetection(workingDirectory)
 
     const cwd = process.cwd()
 
     for (const wd of wds) {
-      await core.group(`run golangci-lint in ${path.relative(cwd, wd)}`, () => runGolangciLint(binPath, wd))
+      await optionalGroup(noGroup, `run golangci-lint in ${path.relative(cwd, wd)}`, () => runGolangciLint(binPath, wd))
     }
 
     return
   }
 
-  await core.group(`run golangci-lint`, () => runGolangciLint(binPath, workingDirectory))
+  await optionalGroup(noGroup, `run golangci-lint`, () => runGolangciLint(binPath, workingDirectory))
+}
+
+async function optionalGroup<T>(noGroup: boolean, name: string, fn: () => Promise<T>): Promise<T> {
+  if (noGroup) {
+    core.info(name)
+
+    return fn()
+  }
+
+  return core.group(name, fn)
 }
 
 export async function run(): Promise<void> {

Description

Adds no-run-logs-group experimental option to disable log grouping during golangci-lint runs. Bumps dependencies (tmp 0.2.5→0.2.7, undici override 6.24→6.27), updates CodeQL action pins, version 9.2.1→9.3.0. Bulk of diff is regenerated dist/* bundles reflecting the undici/tmp upgrades.

Possible Issues

  • dist/* changes must match src + npm run all. Verify bundles regenerated cleanly; hand-editing dist risks drift.
  • optionalGroup with noGroup still runs fn() but skips grouping — errors thrown inside no longer contained by core.group failure semantics. Behavior parity should be confirmed (group vs info logging on failure).

Security Hotspots

  • dist/* undici path-traversal hardening in _assertPath/_getRelativePath (relativePath.startsWith('..') || path.isAbsolute(...)) — improved sanitization vs old startsWith(tmpDir) prefix check, which was bypassable via sibling dirs (/tmp/foo vs /tmp/foobar). Positive change.
  • WebSocket maxFragments cap (default 131072) + payload accumulation check (payloadLength + fragmentsBytes) mitigate memory-exhaustion/DoS. Positive.
  • Cookie SameSite parsing tightened to exact match (=== 'none') vs substring includes — prevents mis-parsing values containing these substrings. Positive.

None introduced by the source change itself.

Changes

Changes

  • .github/workflows/codeql.yaml: bump CodeQL action pins v4.35.4→v4.36.0.
  • README.md: document no-run-logs-group option.
  • action.yml: list available experimental options.
  • src/run.ts: add noGroup flag; extract optionalGroup helper (info-log vs core.group).
  • dist/run/index.js, dist/post_run/index.js: regenerated bundles — source change + undici 6.27 (H1 idle socket validation, parser finish/createError, WS fragment limits) + tmp 0.2.7 path hardening.
  • package.json: version bump, dep bumps.
sequenceDiagram
    participant Action
    participant runLint
    participant optionalGroup
    participant core
    participant golangci

    Action->>runLint: invoke(binPath)
    runLint->>core: getInput("experimental")
    runLint->>runLint: noGroup = includes("no-run-logs-group")
    alt automatic-module-directories
        loop each working dir
            runLint->>optionalGroup: (noGroup, name, fn)
        end
    else single dir
        runLint->>optionalGroup: (noGroup, name, fn)
    end
    alt noGroup
        optionalGroup->>core: info(name)
        optionalGroup->>golangci: fn()
    else grouped
        optionalGroup->>core: group(name, fn)
        core->>golangci: fn()
    end
    golangci-->>optionalGroup: result
    optionalGroup-->>runLint: result
Loading

@jwadolowski
jwadolowski merged commit 04660cc into master Jul 21, 2026
6 checks passed
@jwadolowski
jwadolowski deleted the renovate/golangci-golangci-lint-action-9-x branch July 21, 2026 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant