From d5f35a4d0afdd3c9cee228fb5f9d5fddbc4b6776 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Fri, 10 Apr 2026 14:09:07 +1000 Subject: [PATCH 1/2] fix: remove shell usage from plugin check Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/check-plugin-structure.yml | 38 +++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/.github/workflows/check-plugin-structure.yml b/.github/workflows/check-plugin-structure.yml index 86bab0be6..8556dc811 100644 --- a/.github/workflows/check-plugin-structure.yml +++ b/.github/workflows/check-plugin-structure.yml @@ -21,13 +21,37 @@ jobs: uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 with: script: | - const { execSync } = require('child_process'); const fs = require('fs'); const path = require('path'); const pluginsDir = 'plugins'; const errors = []; + function findSymlinks(rootDir) { + const symlinks = []; + const dirsToScan = [rootDir]; + + while (dirsToScan.length > 0) { + const currentDir = dirsToScan.pop(); + const entries = fs.readdirSync(currentDir, { withFileTypes: true }); + + for (const entry of entries) { + const entryPath = path.join(currentDir, entry.name); + + if (entry.isSymbolicLink()) { + symlinks.push(entryPath); + continue; + } + + if (entry.isDirectory()) { + dirsToScan.push(entryPath); + } + } + } + + return symlinks; + } + if (!fs.existsSync(pluginsDir)) { console.log('No plugins directory found'); return; @@ -63,14 +87,10 @@ jobs: } } - // Check for symlinks anywhere in the plugin directory - try { - const allFiles = execSync(`find "${pluginPath}" -type l`, { encoding: 'utf-8' }).trim(); - if (allFiles) { - errors.push(`${pluginPath} contains symlinks:\n${allFiles}`); - } - } catch (e) { - // find returns non-zero if no matches, ignore + // Check for symlinks anywhere in the plugin directory without invoking a shell + const symlinkPaths = findSymlinks(pluginPath); + if (symlinkPaths.length > 0) { + errors.push(`${pluginPath} contains symlinks:\n${symlinkPaths.join('\n')}`); } } From 1b8dfff4607ab2602dcec6389d71192e6ef4a99e Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Fri, 10 Apr 2026 14:15:03 +1000 Subject: [PATCH 2/2] fix: harden plugin symlink scan Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/check-plugin-structure.yml | 30 ++++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/.github/workflows/check-plugin-structure.yml b/.github/workflows/check-plugin-structure.yml index 8556dc811..dbd097f0e 100644 --- a/.github/workflows/check-plugin-structure.yml +++ b/.github/workflows/check-plugin-structure.yml @@ -33,17 +33,30 @@ jobs: while (dirsToScan.length > 0) { const currentDir = dirsToScan.pop(); - const entries = fs.readdirSync(currentDir, { withFileTypes: true }); + let entries; + + try { + entries = fs.readdirSync(currentDir, { withFileTypes: true }); + } catch (error) { + throw new Error(`Failed to read directory "${currentDir}": ${error.message}`); + } for (const entry of entries) { const entryPath = path.join(currentDir, entry.name); + let stat; - if (entry.isSymbolicLink()) { + try { + stat = fs.lstatSync(entryPath); + } catch (error) { + throw new Error(`Failed to inspect "${entryPath}": ${error.message}`); + } + + if (stat.isSymbolicLink()) { symlinks.push(entryPath); continue; } - if (entry.isDirectory()) { + if (stat.isDirectory()) { dirsToScan.push(entryPath); } } @@ -88,9 +101,14 @@ jobs: } // Check for symlinks anywhere in the plugin directory without invoking a shell - const symlinkPaths = findSymlinks(pluginPath); - if (symlinkPaths.length > 0) { - errors.push(`${pluginPath} contains symlinks:\n${symlinkPaths.join('\n')}`); + try { + const symlinkPaths = findSymlinks(pluginPath); + if (symlinkPaths.length > 0) { + const formattedPaths = symlinkPaths.map(filePath => `\`${filePath}\``).join(', '); + errors.push(`${pluginPath} contains symlinks: ${formattedPaths}`); + } + } catch (error) { + errors.push(`Failed to inspect ${pluginPath} for symlinks: ${error.message}`); } }