Skip to content

feat: extract LGTM processor to external JS file with tests#6074

Merged
Skarlso merged 4 commits intoexternal-secrets:mainfrom
mateenali66:feat/lgtm-external-script
Mar 15, 2026
Merged

feat: extract LGTM processor to external JS file with tests#6074
Skarlso merged 4 commits intoexternal-secrets:mainfrom
mateenali66:feat/lgtm-external-script

Conversation

@mateenali66
Copy link
Copy Markdown
Contributor

@mateenali66 mateenali66 commented Mar 13, 2026

Summary

Addresses #5500.

Moves the inline JavaScript from the Process LGTM Command step in .github/workflows/lgtm.yml into a separate module at .github/scripts/lgtm-processor.js.

Behaviour is unchanged — this is a faithful, line-for-line extraction. No logic modifications, no new features.

Changes:

  • .github/scripts/lgtm-processor.js — the existing inline script, wrapped in an exported async function. Accepts { core, github, context, fs } as parameters.
  • .github/scripts/lgtm-processor-test.js — unit tests for the pure helper logic (CODEOWNERS parsing, file-pattern matching, required-role resolution) using Node.js built-in assert. Run with: node --input-type=module < .github/scripts/lgtm-processor-test.js
  • .github/workflows/lgtm.ymlscript: block replaced with a two-line import:
    const { default: run } = await import(`${process.env.GITHUB_WORKSPACE}/.github/scripts/lgtm-processor.js`);
    await run({ core, github, context, fs: require('fs') });

Summary

This PR extracts the inline LGTM command processor logic from .github/workflows/lgtm.yml into an external, testable module.

Changes:

  • .github/scripts/lgtm-processor.js – Extracted LGTM processor as a default-exported async function accepting { core, github, context, fs }. Handles maintainer verification, required role computation based on CODEOWNERS patterns, and approval/blocking logic with detailed confirmation messages.
  • .github/scripts/lgtm-processor-test.js – Unit tests for pure helper logic: CODEOWNERS parsing, file-pattern matching, and required-role resolution. Runnable via Node.js.
  • .github/workflows/lgtm.yml – Replaces 231-line inline script with 2-line dynamic import and invocation of the external processor.

Behavior: Unchanged; faithful extraction with no logic modifications. Closes #5500.

Moves the inline JavaScript from the 'Process LGTM Command' step in
.github/workflows/lgtm.yml into a separate module at
.github/scripts/lgtm-processor.js. Behaviour is unchanged — this is a
faithful extraction with no logic modifications.

Also adds .github/scripts/lgtm-processor-test.js with unit tests for the
pure helper logic (CODEOWNERS parsing, file-pattern matching, required-role
resolution) using Node.js built-in assert. Run with:
  node --input-type=module < .github/scripts/lgtm-processor-test.js

Closes external-secrets#5500

Signed-off-by: Mateen Anjum <mateenali66@gmail.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 13, 2026

Walkthrough

Introduces an LGTM command processor that automates pull request approval workflows. A new external module parses CODEOWNERS mappings and manages reviewer role-based label approval. The workflow file refactors to use this module instead of inline logic. A test suite validates the parsing and pattern matching functionality.

Changes

Cohort / File(s) Summary
LGTM Processor Module
.github/scripts/lgtm-processor.js
Automates LGTM handling on pull requests by parsing CODEOWNERS mappings, determining required reviewer roles for changed files, and managing label approval or blocking based on maintainer status and role membership verification.
LGTM Processor Tests
.github/scripts/lgtm-processor-test.js
Validates CODEOWNERS parsing, file-pattern matching (exact, prefix, negation), and required reviewer role computation across multiple test scenarios with assertions.
GitHub Workflow
.github/workflows/lgtm.yml
Refactors inline LGTM processing logic to invoke external processor module, removing 229 lines of workflow script code and delegating to lgtm-processor.js.
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can generate a title for your PR based on the changes.

Add @coderabbitai placeholder anywhere in the title of your PR and CodeRabbit will replace it with a title based on the changes in the PR. You can change the placeholder by changing the reviews.auto_title_placeholder setting.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/lgtm.yml (1)

24-25: ⚠️ Potential issue | 🔴 Critical

The workflow no longer checks out the module it imports at runtime.

Only CODEOWNERS.md is present in the sparse checkout, but line 51 imports ${GITHUB_WORKSPACE}/.github/scripts/lgtm-processor.js. On the runner that file is missing, so Process LGTM Command fails before it can parse CODEOWNERS or add the label.

Suggested fix
       with:
         sparse-checkout: |
           CODEOWNERS.md
+          .github/scripts
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/lgtm.yml around lines 24 - 25, The sparse-checkout only
includes CODEOWNERS.md but the workflow job "Process LGTM Command" requires the
lgtm-processor.js script at runtime; update the sparse-checkout config in
lgtm.yml to include the lgtm-processor.js file (or switch to a full checkout) so
the runner can find and import lgtm-processor.js and the job no longer fails due
to a missing file.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/scripts/lgtm-processor-test.js:
- Around line 14-16: The test file duplicates pure helpers (parseCodeowners,
fileMatchesPattern, getRequiredReviewerRoles) so regressions in the real
processor aren’t caught; extract those helper functions into a single shared
module (or export them from the existing processor module) and update both the
processor and .github/scripts/lgtm-processor-test.js to import the shared
helpers instead of reimplementing them, ensuring the exported symbol names
(parseCodeowners, fileMatchesPattern, getRequiredReviewerRoles) are used and
update any require/import statements accordingly.
- Around line 54-64: The forEach callbacks (codeownerMappings.forEach,
roles.forEach, wildcardRoles.forEach) implicitly return the value from
requiredReviewerRoles.add(...) which violates the lint rule; change each arrow
callback to use a block body with explicit statements (e.g., braces and a
semicolon) so they do not return a value — for example convert
roles.forEach(role => requiredReviewerRoles.add(role)) to roles.forEach(role =>
{ requiredReviewerRoles.add(role); }); and likewise use a block for the
codeownerMappings.forEach callback that calls fileMatchesPattern and the inner
roles.forEach, ensuring no value is returned from the outer callback.

In @.github/scripts/lgtm-processor.js:
- Line 14: The file currently uses ESM export syntax for the async function run
which will fail when imported by the workflow as CommonJS; fix this by
converting the export to CommonJS (replace the ESM export with module.exports =
async function run(...) or assign exports.run = run after declaration), or
alternatively make the module truly ESM by adding a package.json with "type":
"module" adjacent to the script or renaming the file to .mjs so Node parses it
as ESM; target the exported symbol run in .github/scripts/lgtm-processor.js when
applying the change.
- Around line 108-115: The forEach callbacks are implicitly returning values
(violating useIterableCallbackReturn); change the concise arrow body that calls
roles.forEach(role => requiredReviewerRoles.add(role)) to a block-bodied arrow
that performs the add without returning a value — e.g., inside the
codeownerMappings.forEach callback (mapping, pattern, file, hasSpecificOwner)
replace roles.forEach(role => requiredReviewerRoles.add(role)) with
roles.forEach(role => { requiredReviewerRoles.add(role); }); ensure no return
value is produced from the forEach callbacks and preserve the existing logic
that sets hasSpecificOwner when a pattern matches.
- Around line 96-99: The current call to github.rest.pulls.listFiles only
fetches one page, so changedFiles misses files when a PR has >30 files; replace
the single-page fetch with a paginated fetch (e.g. use github.paginate or an
explicit loop) to retrieve all files for the given owner, repo and prNumber,
then compute changedFiles by mapping filenames across the full paginated result;
update references around filesResponse/changedFiles to use the full list
returned by github.paginate(github.rest.pulls.listFiles, { owner, repo,
pull_number: prNumber }).

---

Outside diff comments:
In @.github/workflows/lgtm.yml:
- Around line 24-25: The sparse-checkout only includes CODEOWNERS.md but the
workflow job "Process LGTM Command" requires the lgtm-processor.js script at
runtime; update the sparse-checkout config in lgtm.yml to include the
lgtm-processor.js file (or switch to a full checkout) so the runner can find and
import lgtm-processor.js and the job no longer fails due to a missing file.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 50331ac0-d465-4c8a-b059-7a15fc6358d7

📥 Commits

Reviewing files that changed from the base of the PR and between 3b3cf7a and c790c04.

📒 Files selected for processing (3)
  • .github/scripts/lgtm-processor-test.js
  • .github/scripts/lgtm-processor.js
  • .github/workflows/lgtm.yml

Comment on lines +14 to +16
// Helpers duplicated from lgtm-processor.js for unit testing
// (kept in sync manually; tests will catch drift)
// ---------------------------------------------------------------------------
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

These tests are asserting copies of the helpers, not the helpers the workflow executes.

Because parseCodeowners, fileMatchesPattern, and getRequiredReviewerRoles are reimplemented here, a regression in .github/scripts/lgtm-processor.js can still leave this file green. Please move the pure helpers into a shared module, or export them from the processor and import them here instead.

Also applies to: 18-68

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/scripts/lgtm-processor-test.js around lines 14 - 16, The test file
duplicates pure helpers (parseCodeowners, fileMatchesPattern,
getRequiredReviewerRoles) so regressions in the real processor aren’t caught;
extract those helper functions into a single shared module (or export them from
the existing processor module) and update both the processor and
.github/scripts/lgtm-processor-test.js to import the shared helpers instead of
reimplementing them, ensuring the exported symbol names (parseCodeowners,
fileMatchesPattern, getRequiredReviewerRoles) are used and update any
require/import statements accordingly.

Comment on lines +54 to +64
codeownerMappings.forEach(({ pattern, roles }) => {
if (fileMatchesPattern(file, pattern)) {
roles.forEach(role => requiredReviewerRoles.add(role));
hasSpecificOwner = true;
}
});
if (!hasSpecificOwner) hasFilesWithoutSpecificOwners = true;
});

if (hasFilesWithoutSpecificOwners) {
wildcardRoles.forEach(role => requiredReviewerRoles.add(role));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and read lines 54-64
if [ -f ".github/scripts/lgtm-processor-test.js" ]; then
  echo "=== File found. Reading lines 54-64 ==="
  sed -n '54,64p' ".github/scripts/lgtm-processor-test.js"
else
  echo "File not found at expected location. Searching for it..."
  find . -name "lgtm-processor-test.js" -type f
fi

Repository: external-secrets/external-secrets

Length of output: 511


🏁 Script executed:

# Also check the broader context around those lines
if [ -f ".github/scripts/lgtm-processor-test.js" ]; then
  echo "=== Broader context (lines 45-75) ==="
  sed -n '45,75p' ".github/scripts/lgtm-processor-test.js"
fi

Repository: external-secrets/external-secrets

Length of output: 1067


🏁 Script executed:

# Check if this is a test file and look for the exact forEach patterns mentioned
if [ -f ".github/scripts/lgtm-processor-test.js" ]; then
  echo "=== Checking for forEach patterns mentioned in review ==="
  grep -n "roles.forEach\|wildcardRoles.forEach" ".github/scripts/lgtm-processor-test.js"
fi

Repository: external-secrets/external-secrets

Length of output: 272


🌐 Web query:

Biome lint/suspicious/useIterableCallbackReturn rule

💡 Result:

lint/suspicious/useIterableCallbackReturn is a Biome linter rule that enforces consistent return behavior in callbacks passed to iterable/array methods. It’s recommended (enabled by default) and errors by default. (biomejs.dev)

What it checks

Biome expects callbacks to follow the method’s contract: (biomejs.dev)

Callbacks must return a value (you’ll get an error if some paths don’t return):

  • every, filter, find, findIndex, findLast, findLastIndex, flatMap, map, reduce, reduceRight, some, sort, toSorted (and Array.from’s mapping callback) (biomejs.dev)

Callbacks must not return a value:

Notes:

  • async and function* (generator) callbacks are ignored by this rule. (biomejs.dev)

Typical “why am I seeing this?” examples

  • map(() => { doStuff(); }) → missing return in the callback (should always return).
  • forEach(() => { return 1; }) → returning a value from forEach is flagged (should not return a value). (biomejs.dev)

Configure / disable

Enable/disable via biome.json: (biomejs.dev)

{
  "linter": {
    "rules": {
      "suspicious": {
        "useIterableCallbackReturn": "off"
      }
    }
  }
}

Or suppress locally using the rule’s diagnostic category in an ignore comment. (biomejs.dev)

Citations:


🏁 Script executed:

# Let me also check what the .add() method returns
# and verify the implicit return behavior is as described
python3 <<'EOF'
# In JavaScript/TypeScript, Set.prototype.add() returns the Set instance itself
# This means in an arrow function like: role => requiredReviewerRoles.add(role)
# The callback implicitly returns the Set

print("Set.add() behavior:")
print("- Returns: the Set instance (for chaining)")
print("- Used in forEach: callback's return value is ignored")
print("- Issue: implicit return is confusing and suggests a mistake")
print()
print("The suggested fix (using block statement) prevents implicit return:")
print("roles.forEach(role => {")
print("  requiredReviewerRoles.add(role);")
print("});")
print()
print("In block statement form, there's no implicit return unless explicitly stated.")
EOF

Repository: external-secrets/external-secrets

Length of output: 465


Fix implicit returns in forEach callbacks that violate lint/suspicious/useIterableCallbackReturn.

Both callbacks implicitly return the Set from .add(), triggering the Biome lint rule. The forEach method contract requires callbacks to not return a value.

Suggested fix
-      if (fileMatchesPattern(file, pattern)) {
-        roles.forEach(role => requiredReviewerRoles.add(role));
+      if (fileMatchesPattern(file, pattern)) {
+        roles.forEach(role => {
+          requiredReviewerRoles.add(role);
+        });
         hasSpecificOwner = true;
       }
@@
-    wildcardRoles.forEach(role => requiredReviewerRoles.add(role));
+    wildcardRoles.forEach(role => {
+      requiredReviewerRoles.add(role);
+    });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
codeownerMappings.forEach(({ pattern, roles }) => {
if (fileMatchesPattern(file, pattern)) {
roles.forEach(role => requiredReviewerRoles.add(role));
hasSpecificOwner = true;
}
});
if (!hasSpecificOwner) hasFilesWithoutSpecificOwners = true;
});
if (hasFilesWithoutSpecificOwners) {
wildcardRoles.forEach(role => requiredReviewerRoles.add(role));
codeownerMappings.forEach(({ pattern, roles }) => {
if (fileMatchesPattern(file, pattern)) {
roles.forEach(role => {
requiredReviewerRoles.add(role);
});
hasSpecificOwner = true;
}
});
if (!hasSpecificOwner) hasFilesWithoutSpecificOwners = true;
});
if (hasFilesWithoutSpecificOwners) {
wildcardRoles.forEach(role => {
requiredReviewerRoles.add(role);
});
🧰 Tools
🪛 Biome (2.4.6)

[error] 56-56: This callback passed to forEach() iterable method should not return a value.

(lint/suspicious/useIterableCallbackReturn)


[error] 64-64: This callback passed to forEach() iterable method should not return a value.

(lint/suspicious/useIterableCallbackReturn)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/scripts/lgtm-processor-test.js around lines 54 - 64, The forEach
callbacks (codeownerMappings.forEach, roles.forEach, wildcardRoles.forEach)
implicitly return the value from requiredReviewerRoles.add(...) which violates
the lint rule; change each arrow callback to use a block body with explicit
statements (e.g., braces and a semicolon) so they do not return a value — for
example convert roles.forEach(role => requiredReviewerRoles.add(role)) to
roles.forEach(role => { requiredReviewerRoles.add(role); }); and likewise use a
block for the codeownerMappings.forEach callback that calls fileMatchesPattern
and the inner roles.forEach, ensuring no value is returned from the outer
callback.

* @param {object} params.context - GitHub Actions context
* @param {object} params.fs - Node.js fs module
*/
export default async function run({ core, github, context, fs }) {
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Mar 13, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

found=0
for p in .github/scripts/package.json .github/package.json package.json; do
  if [ -f "$p" ]; then
    found=1
    if rg -q '"type"\s*:\s*"module"' "$p"; then
      echo "$p -> type=module"
    else
      echo "$p -> type!=module"
    fi
  fi
done

if [ "$found" -eq 0 ]; then
  echo "No package.json found in the .github/scripts ancestry"
fi

Repository: external-secrets/external-secrets

Length of output: 130


🏁 Script executed:

# Check root package.json existence and ESM type field
if [ -f package.json ]; then
  echo "=== Root package.json exists ==="
  cat package.json | head -20
  if rg -q '"type"\s*:\s*"module"' package.json; then
    echo "Contains: \"type\": \"module\""
  else
    echo "Does NOT contain: \"type\": \"module\""
  fi
else
  echo "Root package.json does NOT exist"
fi

Repository: external-secrets/external-secrets

Length of output: 109


🏁 Script executed:

# Find workflow files that reference lgtm-processor.js
fd -e yml -e yaml .github/workflows | xargs grep -l "lgtm-processor" 2>/dev/null || echo "No workflow files reference lgtm-processor"

Repository: external-secrets/external-secrets

Length of output: 510


🏁 Script executed:

# Find test files that might import lgtm-processor
fd -t f \( -name "*lgtm*" -o -name "*test*" \) .github/scripts 2>/dev/null || echo "No test files in .github/scripts"

Repository: external-secrets/external-secrets

Length of output: 109


🏁 Script executed:

# Verify lgtm-processor.js exists
ls -la .github/scripts/lgtm-processor.js 2>/dev/null || echo "lgtm-processor.js NOT found"

Repository: external-secrets/external-secrets

Length of output: 159


🏁 Script executed:

# Correctly search for workflow files in .github/workflows
fd . '.github/workflows' -e yml -e yaml | head -20

Repository: external-secrets/external-secrets

Length of output: 731


🏁 Script executed:

# Search all workflows for any reference to Node.js scripts execution or lgtm
fd . '.github/workflows' -e yml -e yaml -exec grep -l "node\|lgtm\|scripts" {} \;

Repository: external-secrets/external-secrets

Length of output: 2261


🏁 Script executed:

# Check lgtm.yml
cat .github/workflows/lgtm.yml

Repository: external-secrets/external-secrets

Length of output: 2060


🏁 Script executed:

# Check lgtm-remove-on-update.yml
cat .github/workflows/lgtm-remove-on-update.yml

Repository: external-secrets/external-secrets

Length of output: 1486


🏁 Script executed:

head -20 .github/scripts/lgtm-processor.js

Repository: external-secrets/external-secrets

Length of output: 851


Module format mismatch will cause workflow failure.

Line 14 exports using ESM syntax (export default), but the workflow in lgtm.yml attempts to import it via await import() with no ESM configuration in place. There is no package.json with "type": "module" in .github/scripts/, .github/, or the repository root. Node.js will parse the .js file as CommonJS by default and reject the export default syntax before any LGTM logic executes.

Either add "type": "module" to a package.json in .github/scripts/ (or .github/), rename the file to .mjs, or rewrite using CommonJS (module.exports).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/scripts/lgtm-processor.js at line 14, The file currently uses ESM
export syntax for the async function run which will fail when imported by the
workflow as CommonJS; fix this by converting the export to CommonJS (replace the
ESM export with module.exports = async function run(...) or assign exports.run =
run after declaration), or alternatively make the module truly ESM by adding a
package.json with "type": "module" adjacent to the script or renaming the file
to .mjs so Node parses it as ESM; target the exported symbol run in
.github/scripts/lgtm-processor.js when applying the change.

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.

@mateenali66 I'm not great at Javascript, do you know if this is an actual problem? :DDD
I don't even understand what the problem is. :D

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@Skarlso Not an actual problem — CodeRabbit got confused here.

The file is pure CommonJS: 'use strict' at the top, const fs = require('fs'), and module.exports = lgtmProcessor at the bottom. The workflow imports it with require('./.github/scripts/lgtm-processor.js'). No ESM anywhere.

CodeRabbit invented an export default on line 14 that doesn't exist — that line is just the start of the parseCodeowners function definition. Nothing to fix here.

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.

Thanks, that's what I thought.

Comment on lines +96 to +99
const filesResponse = await github.rest.pulls.listFiles({
owner, repo, pull_number: prNumber
});
const changedFiles = filesResponse.data.map(f => f.filename);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the file and see the context around lines 96-99
fd -t f "lgtm-processor.js" && wc -l .github/scripts/lgtm-processor.js

Repository: external-secrets/external-secrets

Length of output: 114


🏁 Script executed:

# Read the relevant section with context
cat -n .github/scripts/lgtm-processor.js | sed -n '85,115p'

Repository: external-secrets/external-secrets

Length of output: 1498


🏁 Script executed:

# Check the full file to understand the complete flow
cat -n .github/scripts/lgtm-processor.js

Repository: external-secrets/external-secrets

Length of output: 10221


🌐 Web query:

GitHub API REST pulls.listFiles pagination default page size

💡 Result:

For the REST endpoint “List pull request files” (GET /repos/{owner}/{repo}/pulls/{pull_number}/files, i.e. pulls.listFiles):

  • Default page size (per_page) is 30 files if you don’t specify it. [1], [2]
  • You can set per_page up to 100 (then paginate with page=2, page=3, etc., following the response Link header). [1]

Example: .../pulls/123/files?per_page=100&page=1 [1]

Sources: [1] (docs.github.com) [2] (octokit.github.io)

Citations:


🌐 Web query:

Octokit github.paginate() usage pagination utility

💡 Result:

octokit.paginate() is Octokit’s REST pagination utility: it follows the response Link headers and returns one flattened array containing items from all pages. It also exposes octokit.paginate.iterator() for page-by-page streaming (more memory-efficient). [1][2]

Typical usage (Octokit.js)

1) Get all items as one array

import { Octokit } from "octokit";

const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });

const issues = await octokit.paginate("GET /repos/{owner}/{repo}/issues", {
  owner: "octocat",
  repo: "Spoon-Knife",
  per_page: 100,
});

[1]

You can also pass an endpoint method instead of a route string:

const issues = await octokit.paginate(octokit.rest.issues.listForRepo, {
  owner: "octocat",
  repo: "hello-world",
  per_page: 100,
});

[2]

2) Iterate page-by-page (async iterator)

const iterator = octokit.paginate.iterator(octokit.rest.issues.listForRepo, {
  owner: "octocat",
  repo: "hello-world",
  per_page: 100,
});

for await (const { data: issues } of iterator) {
  for (const issue of issues) console.log(issue.number, issue.title);
}

[2]

3) Optional “map” callback (transform / early-stop)

GitHub’s docs note you can pass an optional map function to transform results and/or stop early (and paginate.iterator() if you don’t want to fetch everything at once). [1]

If you’re composing Octokit manually

Pagination comes from @octokit/plugin-paginate-rest (it adds .paginate() / .paginate.iterator()), e.g.:

import { Octokit } from "@octokit/core";
import { paginateRest } from "@octokit/plugin-paginate-rest";

const MyOctokit = Octokit.plugin(paginateRest);
const octokit = new MyOctokit({ auth: "secret123" });

const issues = await octokit.paginate("GET /repos/{owner}/{repo}/issues", {
  owner: "octocat",
  repo: "hello-world",
  per_page: 100,
});

[3]

Sources: GitHub REST pagination docs [1], Octokit.js README [2], @octokit/plugin-paginate-rest README [3].


Paginate the PR file list before computing reviewer roles.

Lines 96-99 only inspect the first page from pulls.listFiles. GitHub's REST API defaults to 30 items per page, so PRs with more than 30 changed files miss the remaining files. This causes the workflow to undercompute required roles and can authorize /lgtm from the wrong team.

Suggested fix
-  const filesResponse = await github.rest.pulls.listFiles({
-    owner, repo, pull_number: prNumber
-  });
-  const changedFiles = filesResponse.data.map(f => f.filename);
+  const files = await github.paginate(github.rest.pulls.listFiles, {
+    owner,
+    repo,
+    pull_number: prNumber,
+    per_page: 100
+  });
+  const changedFiles = files.map(file => file.filename);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const filesResponse = await github.rest.pulls.listFiles({
owner, repo, pull_number: prNumber
});
const changedFiles = filesResponse.data.map(f => f.filename);
const files = await github.paginate(github.rest.pulls.listFiles, {
owner,
repo,
pull_number: prNumber,
per_page: 100
});
const changedFiles = files.map(file => file.filename);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/scripts/lgtm-processor.js around lines 96 - 99, The current call to
github.rest.pulls.listFiles only fetches one page, so changedFiles misses files
when a PR has >30 files; replace the single-page fetch with a paginated fetch
(e.g. use github.paginate or an explicit loop) to retrieve all files for the
given owner, repo and prNumber, then compute changedFiles by mapping filenames
across the full paginated result; update references around
filesResponse/changedFiles to use the full list returned by
github.paginate(github.rest.pulls.listFiles, { owner, repo, pull_number:
prNumber }).

Comment on lines +108 to +115
codeownerMappings.forEach(mapping => {
const { pattern, roles } = mapping;
// Match pattern (handle both exact matches and directory patterns)
// This handles hierarchical matching where broader patterns can cover more specific paths
if (file === pattern ||
file.startsWith(pattern.endsWith('/') ? pattern : pattern + '/')) {
roles.forEach(role => requiredReviewerRoles.add(role));
hasSpecificOwner = true;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's check if the file exists and read the relevant lines
cat -n .github/scripts/lgtm-processor.js | sed -n '100,120p'

Repository: external-secrets/external-secrets

Length of output: 1087


🏁 Script executed:

# Look for Biome configuration files
find . -name "biome.json" -o -name "biome.jsonc" -o -name ".biomeignore" | head -20

Repository: external-secrets/external-secrets

Length of output: 89


🏁 Script executed:

# Check for Biome configuration and rules
rg "useIterableCallbackReturn" -t json -t js

Repository: external-secrets/external-secrets

Length of output: 59


🏁 Script executed:

cat ./biome.json

Repository: external-secrets/external-secrets

Length of output: 1851


🏁 Script executed:

web_search
Biome useIterableCallbackReturn rule documentation

Repository: external-secrets/external-secrets

Length of output: 171


🌐 Web query:

Biome useIterableCallbackReturn rule what does it check

💡 Result:

Biome’s lint/suspicious/useIterableCallbackReturn rule enforces consistent return behavior inside callbacks passed to common iterable/array methods: for methods whose callback result is used, the callback should always return a value (e.g. map, filter, find, reduce, some, every, sort, etc.). It also flags the opposite case for forEach: returning a value from a forEach callback is disallowed (because the return value is ignored). Async and generator callbacks are ignored. [1]

Optionally, since Biome v2.4.0, you can set checkForEach: false to skip checking forEach callbacks for returned values. [1] [2]


Line 114 violates Biome's useIterableCallbackReturn rule.

The arrow function callback implicitly returns the Set from .add(), but forEach callbacks should not return values. Convert to a block body:

Suggested fix
-        roles.forEach(role => requiredReviewerRoles.add(role));
+        roles.forEach(role => {
+          requiredReviewerRoles.add(role);
+        });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
codeownerMappings.forEach(mapping => {
const { pattern, roles } = mapping;
// Match pattern (handle both exact matches and directory patterns)
// This handles hierarchical matching where broader patterns can cover more specific paths
if (file === pattern ||
file.startsWith(pattern.endsWith('/') ? pattern : pattern + '/')) {
roles.forEach(role => requiredReviewerRoles.add(role));
hasSpecificOwner = true;
codeownerMappings.forEach(mapping => {
const { pattern, roles } = mapping;
// Match pattern (handle both exact matches and directory patterns)
// This handles hierarchical matching where broader patterns can cover more specific paths
if (file === pattern ||
file.startsWith(pattern.endsWith('/') ? pattern : pattern + '/')) {
roles.forEach(role => {
requiredReviewerRoles.add(role);
});
hasSpecificOwner = true;
🧰 Tools
🪛 Biome (2.4.6)

[error] 114-114: This callback passed to forEach() iterable method should not return a value.

(lint/suspicious/useIterableCallbackReturn)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/scripts/lgtm-processor.js around lines 108 - 115, The forEach
callbacks are implicitly returning values (violating useIterableCallbackReturn);
change the concise arrow body that calls roles.forEach(role =>
requiredReviewerRoles.add(role)) to a block-bodied arrow that performs the add
without returning a value — e.g., inside the codeownerMappings.forEach callback
(mapping, pattern, file, hasSpecificOwner) replace roles.forEach(role =>
requiredReviewerRoles.add(role)) with roles.forEach(role => {
requiredReviewerRoles.add(role); }); ensure no return value is produced from the
forEach callbacks and preserve the existing logic that sets hasSpecificOwner
when a pattern matches.

@Skarlso
Copy link
Copy Markdown
Contributor

Skarlso commented Mar 14, 2026

Thanks! 🙇

After this, we can improve the existing script. :) It will be much more visible! Thank you! :)

@sonarqubecloud
Copy link
Copy Markdown

@Skarlso Skarlso merged commit cdea53a into external-secrets:main Mar 15, 2026
9 checks passed
@Skarlso
Copy link
Copy Markdown
Contributor

Skarlso commented Mar 15, 2026

@mateenali66 Now that this is merged, will you add the check that prevents it from doing something if the label doesn't exist? :)

mateenali66 added a commit to mateenali66/external-secrets that referenced this pull request Mar 15, 2026
If the lgtm label is missing from the repo, core.setFailed() is called
with a descriptive error before any other logic runs. Resolves the
follow-up requested by @Skarlso after external-secrets#6074 was merged.

Signed-off-by: Mateen Anjum <mateenali66@gmail.com>
@mateenali66
Copy link
Copy Markdown
Contributor Author

@Skarlso Done! Opened the label existence check as a follow-up: #6078

AlexOQ pushed a commit to AlexOQ/external-secrets that referenced this pull request Mar 18, 2026
…-secrets#6074)

Co-authored-by: Gergely Bräutigam <gergely.brautigam@sap.com>
Signed-off-by: AlexOQ <30403857+AlexOQ@users.noreply.github.com>
alexlebens pushed a commit to alexlebens/infrastructure that referenced this pull request Mar 20, 2026
…2.2.0 (#4923)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [external-secrets/external-secrets](https://github.com/external-secrets/external-secrets) | minor | `v2.1.0` → `v2.2.0` |

---

> ⚠️ **Warning**
>
> Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/2) for more information.

---

### Release Notes

<details>
<summary>external-secrets/external-secrets (external-secrets/external-secrets)</summary>

### [`v2.2.0`](https://github.com/external-secrets/external-secrets/releases/tag/v2.2.0)

[Compare Source](external-secrets/external-secrets@v2.1.0...v2.2.0)

Image: `ghcr.io/external-secrets/external-secrets:v2.2.0`
Image: `ghcr.io/external-secrets/external-secrets:v2.2.0-ubi`
Image: `ghcr.io/external-secrets/external-secrets:v2.2.0-ubi-boringssl`

<!-- Release notes generated using configuration in .github/release.yml at main -->

#### What's Changed

##### General

- chore: release charts v2.1.0 by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6030](external-secrets/external-secrets#6030)
- chore: fix the stability doc by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6035](external-secrets/external-secrets#6035)
- fix(security): Fix vulnerabilities by [@&#8203;othomann](https://github.com/othomann) in [#&#8203;6052](external-secrets/external-secrets#6052)
- fix(aws): sync tags and resource policy even when secret value unchanged by [@&#8203;evs-secops](https://github.com/evs-secops) in [#&#8203;6025](external-secrets/external-secrets#6025)
- fix: publish now uses docker build v4 which required some changes by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6062](external-secrets/external-secrets#6062)
- feat(gcpsm): auto-detect projectID from GCP metadata server by [@&#8203;patjlm](https://github.com/patjlm) in [#&#8203;5922](external-secrets/external-secrets#5922)
- chore(templating): Remove years in license and their checks by [@&#8203;evrardj-roche](https://github.com/evrardj-roche) in [#&#8203;5955](external-secrets/external-secrets#5955)
- docs: Add Roche to official ADOPTERS by [@&#8203;evrardj-roche](https://github.com/evrardj-roche) in [#&#8203;6076](external-secrets/external-secrets#6076)
- feat: Add Last Sync column to ExternalSecret and PushSecret printers by [@&#8203;jaruwat-panturat](https://github.com/jaruwat-panturat) in [#&#8203;6068](external-secrets/external-secrets#6068)
- fix(onepassword): support native item IDs by [@&#8203;chadxz](https://github.com/chadxz) in [#&#8203;6073](external-secrets/external-secrets#6073)
- feat: extract LGTM processor to external JS file with tests by [@&#8203;mateenali66](https://github.com/mateenali66) in [#&#8203;6074](external-secrets/external-secrets#6074)
- feat: fail fast if LGTM label does not exist in repository by [@&#8203;mateenali66](https://github.com/mateenali66) in [#&#8203;6078](external-secrets/external-secrets#6078)
- feat(passbolt): add support for Passbolt V5 API by [@&#8203;cedricherzog-passbolt](https://github.com/cedricherzog-passbolt) in [#&#8203;5919](external-secrets/external-secrets#5919)
- fix(infisical): dataFrom.find.path should filter by secret path not name by [@&#8203;johnvox](https://github.com/johnvox) in [#&#8203;6086](external-secrets/external-secrets#6086)
- fix: disable the priority queue which misbehaves at scale by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6083](external-secrets/external-secrets#6083)
- chore: update go version to 1.26.1 by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6072](external-secrets/external-secrets#6072)
- docs(aws): fix PushSecret metadata indentation in resource policy exa... by [@&#8203;Br1an67](https://github.com/Br1an67) in [#&#8203;6056](external-secrets/external-secrets#6056)
- fix(aws): prevent EC2 IMDS fallback when explicit credentials are pro... by [@&#8203;Br1an67](https://github.com/Br1an67) in [#&#8203;6036](external-secrets/external-secrets#6036)
- feat(templating): Add certSANs function to extract SANs from certificates by [@&#8203;mzdeb](https://github.com/mzdeb) in [#&#8203;6058](external-secrets/external-secrets#6058)
- docs: document template.metadata labels/annotations behavior by [@&#8203;lucpas](https://github.com/lucpas) in [#&#8203;6102](external-secrets/external-secrets#6102)
- fix: CODEOWNERS are seriously out of date by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6106](external-secrets/external-secrets#6106)
- feat(helm): add readinessProbe support for external-secrets deployment by [@&#8203;AlexOQ](https://github.com/AlexOQ) in [#&#8203;5831](external-secrets/external-secrets#5831)
- fix: update grpc for CVE-2026-33186 by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6108](external-secrets/external-secrets#6108)
- feat(azurekv): add expiration time to azure kv secret by [@&#8203;muraliavarma](https://github.com/muraliavarma) in [#&#8203;5935](external-secrets/external-secrets#5935)
- feat: add path to cloud.ru provider by [@&#8203;heavyandrew](https://github.com/heavyandrew) in [#&#8203;5952](external-secrets/external-secrets#5952)
- fix(add-eso-version): fix separator line pattern in add\_eso\_version.sh script by [@&#8203;riccardomc](https://github.com/riccardomc) in [#&#8203;6113](external-secrets/external-secrets#6113)

##### Dependencies

- chore(deps): bump zizmorcore/zizmor-action from 0.5.0 to 0.5.2 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6038](external-secrets/external-secrets#6038)
- chore(deps): bump charset-normalizer from 3.4.4 to 3.4.5 in /hack/api-docs by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6047](external-secrets/external-secrets#6047)
- chore(deps): bump platformdirs from 4.9.2 to 4.9.4 in /hack/api-docs by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6050](external-secrets/external-secrets#6050)
- chore(deps): bump mkdocs-material from 9.7.3 to 9.7.4 in /hack/api-docs by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6049](external-secrets/external-secrets#6049)
- chore(deps): bump github/codeql-action from 4.32.4 to 4.32.6 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6039](external-secrets/external-secrets#6039)
- chore(deps): bump step-security/harden-runner from 2.15.0 to 2.15.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6043](external-secrets/external-secrets#6043)
- chore(deps): bump actions/dependency-review-action from 4.8.3 to 4.9.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6040](external-secrets/external-secrets#6040)
- chore(deps): bump crazy-max/ghaction-import-gpg from 6.3.0 to 7.0.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6044](external-secrets/external-secrets#6044)
- chore(deps): bump docker/login-action from 3.7.0 to 4.0.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6042](external-secrets/external-secrets#6042)
- chore(deps): bump docker/setup-buildx-action from 3.12.0 to 4.0.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6041](external-secrets/external-secrets#6041)
- chore(deps): bump docker/setup-qemu-action from 3.7.0 to 4.0.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6046](external-secrets/external-secrets#6046)
- chore(deps): bump aquasecurity/trivy-action from 0.34.1 to 0.35.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6048](external-secrets/external-secrets#6048)
- chore(deps): bump anchore/sbom-action from 0.23.0 to 0.23.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6093](external-secrets/external-secrets#6093)
- chore(deps): bump distroless/static from `28efbe9` to `47b2d72` by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6088](external-secrets/external-secrets#6088)
- chore(deps): bump ubi9/ubi from `cecb1cd` to `6ed9f6f` by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6087](external-secrets/external-secrets#6087)
- chore(deps): bump mkdocs-material from 9.7.4 to 9.7.5 in /hack/api-docs by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6096](external-secrets/external-secrets#6096)
- chore(deps): bump tornado from 6.5.4 to 6.5.5 in /hack/api-docs by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6094](external-secrets/external-secrets#6094)
- chore(deps): bump charset-normalizer from 3.4.5 to 3.4.6 in /hack/api-docs by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6095](external-secrets/external-secrets#6095)
- chore(deps): bump step-security/harden-runner from 2.15.1 to 2.16.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6089](external-secrets/external-secrets#6089)
- chore(deps): bump sigstore/cosign-installer from 4.0.0 to 4.1.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6092](external-secrets/external-secrets#6092)
- chore(deps): bump softprops/action-gh-release from 2.5.0 to 2.6.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6090](external-secrets/external-secrets#6090)
- chore(deps): bump actions/create-github-app-token from 2.2.1 to 3.0.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6091](external-secrets/external-secrets#6091)

#### New Contributors

- [@&#8203;othomann](https://github.com/othomann) made their first contribution in [#&#8203;6052](external-secrets/external-secrets#6052)
- [@&#8203;evs-secops](https://github.com/evs-secops) made their first contribution in [#&#8203;6025](external-secrets/external-secrets#6025)
- [@&#8203;patjlm](https://github.com/patjlm) made their first contribution in [#&#8203;5922](external-secrets/external-secrets#5922)
- [@&#8203;jaruwat-panturat](https://github.com/jaruwat-panturat) made their first contribution in [#&#8203;6068](external-secrets/external-secrets#6068)
- [@&#8203;chadxz](https://github.com/chadxz) made their first contribution in [#&#8203;6073](external-secrets/external-secrets#6073)
- [@&#8203;mateenali66](https://github.com/mateenali66) made their first contribution in [#&#8203;6074](external-secrets/external-secrets#6074)
- [@&#8203;cedricherzog-passbolt](https://github.com/cedricherzog-passbolt) made their first contribution in [#&#8203;5919](external-secrets/external-secrets#5919)
- [@&#8203;johnvox](https://github.com/johnvox) made their first contribution in [#&#8203;6086](external-secrets/external-secrets#6086)
- [@&#8203;Br1an67](https://github.com/Br1an67) made their first contribution in [#&#8203;6056](external-secrets/external-secrets#6056)
- [@&#8203;mzdeb](https://github.com/mzdeb) made their first contribution in [#&#8203;6058](external-secrets/external-secrets#6058)
- [@&#8203;lucpas](https://github.com/lucpas) made their first contribution in [#&#8203;6102](external-secrets/external-secrets#6102)
- [@&#8203;AlexOQ](https://github.com/AlexOQ) made their first contribution in [#&#8203;5831](external-secrets/external-secrets#5831)
- [@&#8203;muraliavarma](https://github.com/muraliavarma) made their first contribution in [#&#8203;5935](external-secrets/external-secrets#5935)
- [@&#8203;heavyandrew](https://github.com/heavyandrew) made their first contribution in [#&#8203;5952](external-secrets/external-secrets#5952)

**Full Changelog**: <external-secrets/external-secrets@v2.1.0...v2.2.0>

</details>

---

### Configuration

📅 **Schedule**: 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.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My41OS4yIiwidXBkYXRlZEluVmVyIjoiNDMuNTkuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW1hZ2UiXX0=-->

Reviewed-on: https://gitea.alexlebens.dev/alexlebens/infrastructure/pulls/4923
Co-authored-by: Renovate Bot <renovate-bot@alexlebens.net>
Co-committed-by: Renovate Bot <renovate-bot@alexlebens.net>
alexlebens pushed a commit to alexlebens/infrastructure that referenced this pull request Mar 20, 2026
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [external-secrets](https://github.com/external-secrets/external-secrets) | minor | `2.1.0` → `2.2.0` |

---

> ⚠️ **Warning**
>
> Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/2) for more information.

---

### Release Notes

<details>
<summary>external-secrets/external-secrets (external-secrets)</summary>

### [`v2.2.0`](https://github.com/external-secrets/external-secrets/releases/tag/v2.2.0)

[Compare Source](external-secrets/external-secrets@v2.1.0...v2.2.0)

Image: `ghcr.io/external-secrets/external-secrets:v2.2.0`
Image: `ghcr.io/external-secrets/external-secrets:v2.2.0-ubi`
Image: `ghcr.io/external-secrets/external-secrets:v2.2.0-ubi-boringssl`

<!-- Release notes generated using configuration in .github/release.yml at main -->

##### What's Changed

##### General

- chore: release charts v2.1.0 by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6030](external-secrets/external-secrets#6030)
- chore: fix the stability doc by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6035](external-secrets/external-secrets#6035)
- fix(security): Fix vulnerabilities by [@&#8203;othomann](https://github.com/othomann) in [#&#8203;6052](external-secrets/external-secrets#6052)
- fix(aws): sync tags and resource policy even when secret value unchanged by [@&#8203;evs-secops](https://github.com/evs-secops) in [#&#8203;6025](external-secrets/external-secrets#6025)
- fix: publish now uses docker build v4 which required some changes by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6062](external-secrets/external-secrets#6062)
- feat(gcpsm): auto-detect projectID from GCP metadata server by [@&#8203;patjlm](https://github.com/patjlm) in [#&#8203;5922](external-secrets/external-secrets#5922)
- chore(templating): Remove years in license and their checks by [@&#8203;evrardj-roche](https://github.com/evrardj-roche) in [#&#8203;5955](external-secrets/external-secrets#5955)
- docs: Add Roche to official ADOPTERS by [@&#8203;evrardj-roche](https://github.com/evrardj-roche) in [#&#8203;6076](external-secrets/external-secrets#6076)
- feat: Add Last Sync column to ExternalSecret and PushSecret printers by [@&#8203;jaruwat-panturat](https://github.com/jaruwat-panturat) in [#&#8203;6068](external-secrets/external-secrets#6068)
- fix(onepassword): support native item IDs by [@&#8203;chadxz](https://github.com/chadxz) in [#&#8203;6073](external-secrets/external-secrets#6073)
- feat: extract LGTM processor to external JS file with tests by [@&#8203;mateenali66](https://github.com/mateenali66) in [#&#8203;6074](external-secrets/external-secrets#6074)
- feat: fail fast if LGTM label does not exist in repository by [@&#8203;mateenali66](https://github.com/mateenali66) in [#&#8203;6078](external-secrets/external-secrets#6078)
- feat(passbolt): add support for Passbolt V5 API by [@&#8203;cedricherzog-passbolt](https://github.com/cedricherzog-passbolt) in [#&#8203;5919](external-secrets/external-secrets#5919)
- fix(infisical): dataFrom.find.path should filter by secret path not name by [@&#8203;johnvox](https://github.com/johnvox) in [#&#8203;6086](external-secrets/external-secrets#6086)
- fix: disable the priority queue which misbehaves at scale by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6083](external-secrets/external-secrets#6083)
- chore: update go version to 1.26.1 by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6072](external-secrets/external-secrets#6072)
- docs(aws): fix PushSecret metadata indentation in resource policy exa... by [@&#8203;Br1an67](https://github.com/Br1an67) in [#&#8203;6056](external-secrets/external-secrets#6056)
- fix(aws): prevent EC2 IMDS fallback when explicit credentials are pro... by [@&#8203;Br1an67](https://github.com/Br1an67) in [#&#8203;6036](external-secrets/external-secrets#6036)
- feat(templating): Add certSANs function to extract SANs from certificates by [@&#8203;mzdeb](https://github.com/mzdeb) in [#&#8203;6058](external-secrets/external-secrets#6058)
- docs: document template.metadata labels/annotations behavior by [@&#8203;lucpas](https://github.com/lucpas) in [#&#8203;6102](external-secrets/external-secrets#6102)
- fix: CODEOWNERS are seriously out of date by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6106](external-secrets/external-secrets#6106)
- feat(helm): add readinessProbe support for external-secrets deployment by [@&#8203;AlexOQ](https://github.com/AlexOQ) in [#&#8203;5831](external-secrets/external-secrets#5831)
- fix: update grpc for CVE-2026-33186 by [@&#8203;Skarlso](https://github.com/Skarlso) in [#&#8203;6108](external-secrets/external-secrets#6108)
- feat(azurekv): add expiration time to azure kv secret by [@&#8203;muraliavarma](https://github.com/muraliavarma) in [#&#8203;5935](external-secrets/external-secrets#5935)
- feat: add path to cloud.ru provider by [@&#8203;heavyandrew](https://github.com/heavyandrew) in [#&#8203;5952](external-secrets/external-secrets#5952)
- fix(add-eso-version): fix separator line pattern in add\_eso\_version.sh script by [@&#8203;riccardomc](https://github.com/riccardomc) in [#&#8203;6113](external-secrets/external-secrets#6113)

##### Dependencies

- chore(deps): bump zizmorcore/zizmor-action from 0.5.0 to 0.5.2 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6038](external-secrets/external-secrets#6038)
- chore(deps): bump charset-normalizer from 3.4.4 to 3.4.5 in /hack/api-docs by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6047](external-secrets/external-secrets#6047)
- chore(deps): bump platformdirs from 4.9.2 to 4.9.4 in /hack/api-docs by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6050](external-secrets/external-secrets#6050)
- chore(deps): bump mkdocs-material from 9.7.3 to 9.7.4 in /hack/api-docs by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6049](external-secrets/external-secrets#6049)
- chore(deps): bump github/codeql-action from 4.32.4 to 4.32.6 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6039](external-secrets/external-secrets#6039)
- chore(deps): bump step-security/harden-runner from 2.15.0 to 2.15.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6043](external-secrets/external-secrets#6043)
- chore(deps): bump actions/dependency-review-action from 4.8.3 to 4.9.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6040](external-secrets/external-secrets#6040)
- chore(deps): bump crazy-max/ghaction-import-gpg from 6.3.0 to 7.0.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6044](external-secrets/external-secrets#6044)
- chore(deps): bump docker/login-action from 3.7.0 to 4.0.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6042](external-secrets/external-secrets#6042)
- chore(deps): bump docker/setup-buildx-action from 3.12.0 to 4.0.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6041](external-secrets/external-secrets#6041)
- chore(deps): bump docker/setup-qemu-action from 3.7.0 to 4.0.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6046](external-secrets/external-secrets#6046)
- chore(deps): bump aquasecurity/trivy-action from 0.34.1 to 0.35.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6048](external-secrets/external-secrets#6048)
- chore(deps): bump anchore/sbom-action from 0.23.0 to 0.23.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6093](external-secrets/external-secrets#6093)
- chore(deps): bump distroless/static from `28efbe9` to `47b2d72` by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6088](external-secrets/external-secrets#6088)
- chore(deps): bump ubi9/ubi from `cecb1cd` to `6ed9f6f` by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6087](external-secrets/external-secrets#6087)
- chore(deps): bump mkdocs-material from 9.7.4 to 9.7.5 in /hack/api-docs by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6096](external-secrets/external-secrets#6096)
- chore(deps): bump tornado from 6.5.4 to 6.5.5 in /hack/api-docs by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6094](external-secrets/external-secrets#6094)
- chore(deps): bump charset-normalizer from 3.4.5 to 3.4.6 in /hack/api-docs by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6095](external-secrets/external-secrets#6095)
- chore(deps): bump step-security/harden-runner from 2.15.1 to 2.16.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6089](external-secrets/external-secrets#6089)
- chore(deps): bump sigstore/cosign-installer from 4.0.0 to 4.1.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6092](external-secrets/external-secrets#6092)
- chore(deps): bump softprops/action-gh-release from 2.5.0 to 2.6.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6090](external-secrets/external-secrets#6090)
- chore(deps): bump actions/create-github-app-token from 2.2.1 to 3.0.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;6091](external-secrets/external-secrets#6091)

##### New Contributors

- [@&#8203;othomann](https://github.com/othomann) made their first contribution in [#&#8203;6052](external-secrets/external-secrets#6052)
- [@&#8203;evs-secops](https://github.com/evs-secops) made their first contribution in [#&#8203;6025](external-secrets/external-secrets#6025)
- [@&#8203;patjlm](https://github.com/patjlm) made their first contribution in [#&#8203;5922](external-secrets/external-secrets#5922)
- [@&#8203;jaruwat-panturat](https://github.com/jaruwat-panturat) made their first contribution in [#&#8203;6068](external-secrets/external-secrets#6068)
- [@&#8203;chadxz](https://github.com/chadxz) made their first contribution in [#&#8203;6073](external-secrets/external-secrets#6073)
- [@&#8203;mateenali66](https://github.com/mateenali66) made their first contribution in [#&#8203;6074](external-secrets/external-secrets#6074)
- [@&#8203;cedricherzog-passbolt](https://github.com/cedricherzog-passbolt) made their first contribution in [#&#8203;5919](external-secrets/external-secrets#5919)
- [@&#8203;johnvox](https://github.com/johnvox) made their first contribution in [#&#8203;6086](external-secrets/external-secrets#6086)
- [@&#8203;Br1an67](https://github.com/Br1an67) made their first contribution in [#&#8203;6056](external-secrets/external-secrets#6056)
- [@&#8203;mzdeb](https://github.com/mzdeb) made their first contribution in [#&#8203;6058](external-secrets/external-secrets#6058)
- [@&#8203;lucpas](https://github.com/lucpas) made their first contribution in [#&#8203;6102](external-secrets/external-secrets#6102)
- [@&#8203;AlexOQ](https://github.com/AlexOQ) made their first contribution in [#&#8203;5831](external-secrets/external-secrets#5831)
- [@&#8203;muraliavarma](https://github.com/muraliavarma) made their first contribution in [#&#8203;5935](external-secrets/external-secrets#5935)
- [@&#8203;heavyandrew](https://github.com/heavyandrew) made their first contribution in [#&#8203;5952](external-secrets/external-secrets#5952)

**Full Changelog**: <external-secrets/external-secrets@v2.1.0...v2.2.0>

</details>

---

### Configuration

📅 **Schedule**: 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.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My41OS4yIiwidXBkYXRlZEluVmVyIjoiNDMuNTkuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiY2hhcnQiXX0=-->

Reviewed-on: https://gitea.alexlebens.dev/alexlebens/infrastructure/pulls/4927
Co-authored-by: Renovate Bot <renovate-bot@alexlebens.net>
Co-committed-by: Renovate Bot <renovate-bot@alexlebens.net>
dsp0x4 pushed a commit to dsp0x4/external-secrets that referenced this pull request Mar 22, 2026
…-secrets#6074)

Co-authored-by: Gergely Bräutigam <gergely.brautigam@sap.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/github-actions kind/feature Categorizes issue or PR as related to a new feature. size/l

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

feat: switch the lgmt parser to external javascript file and write tests for it

2 participants