From 6f5b8a56613daa153b8f9cba5047d20f01f0a8e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B0=8F=E7=88=AC=E7=9A=84=E8=80=81=E7=B2=89=E4=B8=9D?=
<727842003@qq.com>
Date: Sun, 11 Oct 2026 14:06:05 +0800
Subject: [PATCH 1/2] fix: restore complete security checks for dependency
updates
---
.eslintignore | 1 -
.eslintrc | 98 +-
.github/actions/corpus/action.yml | 10 +-
.github/workflows/ci.yml | 5 +-
.github/workflows/publish.yml | 3 +-
.github/workflows/rebase.yml | 18 +-
.github/workflows/require-allow-edits.yml | 4 +
.github/workflows/security-regression.yml | 2 +
bin/xlsx.njs | 1 -
eslint.config.mjs | 28 +
index.html | 1 -
package-lock.json | 1213 +++++++++++----------
package.json | 8 +-
tests/tooling-config.mjs | 51 +
14 files changed, 846 insertions(+), 597 deletions(-)
delete mode 100644 .eslintignore
create mode 100644 eslint.config.mjs
create mode 100644 tests/tooling-config.mjs
diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index ce7ed79a..00000000
--- a/.eslintignore
+++ /dev/null
@@ -1 +0,0 @@
-xlsx.js
diff --git a/.eslintrc b/.eslintrc
index dfb762e5..0db3b961 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,26 +1,96 @@
{
- "env": { "shared-node-browser":true },
+ "env": {
+ "shared-node-browser": true
+ },
"globals": {},
"parserOptions": {
"ecmaVersion": 3
},
- "plugins": [ "html", "json" ],
- "extends": "eslint:recommended",
+ "plugins": [
+ "html",
+ "json"
+ ],
"rules": {
- "comma-style": [ 2, "last" ],
- "comma-dangle": [ 2, "never" ],
- "curly": 0,
- "no-bitwise": 0,
+ "constructor-super": "error",
+ "for-direction": "error",
+ "getter-return": "error",
+ "no-async-promise-executor": "error",
+ "no-case-declarations": "error",
+ "no-class-assign": "error",
+ "no-compare-neg-zero": "error",
"no-cond-assign": 1,
- "no-console": 0,
+ "no-const-assign": "error",
+ "no-constant-condition": "error",
"no-control-regex": 0,
- "no-unused-vars": 1,
+ "no-debugger": "error",
+ "no-delete-var": "error",
+ "no-dupe-args": "error",
+ "no-dupe-class-members": "error",
+ "no-dupe-else-if": "error",
+ "no-dupe-keys": "error",
+ "no-duplicate-case": "error",
"no-empty": 0,
- "no-trailing-spaces": 2,
- "no-use-before-define": [ 1, {
- "functions":false, "classes":true, "variables":false
- }],
+ "no-empty-character-class": "error",
+ "no-empty-pattern": "error",
+ "no-ex-assign": "error",
+ "no-extra-boolean-cast": "error",
+ "no-extra-semi": "error",
+ "no-fallthrough": "error",
+ "no-func-assign": "error",
+ "no-global-assign": "error",
+ "no-import-assign": "error",
+ "no-inner-declarations": "error",
+ "no-invalid-regexp": "error",
+ "no-irregular-whitespace": "error",
+ "no-misleading-character-class": "error",
+ "no-mixed-spaces-and-tabs": "error",
+ "no-obj-calls": "error",
+ "no-octal": "error",
+ "no-prototype-builtins": "error",
+ "no-redeclare": "error",
+ "no-regex-spaces": "error",
+ "no-self-assign": "error",
+ "no-setter-return": "error",
+ "no-shadow-restricted-names": "error",
+ "no-sparse-arrays": "error",
+ "no-this-before-super": "error",
+ "no-undef": "error",
+ "no-unexpected-multiline": "error",
+ "no-unreachable": "error",
+ "no-unsafe-finally": "error",
+ "no-unsafe-negation": "error",
+ "no-unused-labels": "error",
+ "no-unused-vars": 1,
+ "no-useless-catch": "error",
"no-useless-escape": 0,
- "semi": [ 2, "always" ]
+ "no-with": "error",
+ "require-yield": "error",
+ "use-isnan": "error",
+ "valid-typeof": "error",
+ "no-new-native-nonconstructor": "error",
+ "comma-style": [
+ 2,
+ "last"
+ ],
+ "comma-dangle": [
+ 2,
+ "never"
+ ],
+ "curly": 0,
+ "no-bitwise": 0,
+ "no-console": 0,
+ "no-trailing-spaces": 2,
+ "no-use-before-define": [
+ 1,
+ {
+ "functions": false,
+ "classes": true,
+ "variables": false
+ }
+ ],
+ "semi": [
+ 2,
+ "always"
+ ]
}
}
diff --git a/.github/actions/corpus/action.yml b/.github/actions/corpus/action.yml
index 18415a55..ef021316 100644
--- a/.github/actions/corpus/action.yml
+++ b/.github/actions/corpus/action.yml
@@ -1,15 +1,9 @@
name: Verified SheetJS corpus
-description: Restore the pinned official corpus without mutable SVN downloads
+description: Download and verify the pinned official corpus without shared cache writes
runs:
using: composite
steps:
- - uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5
- id: archive
- with:
- path: ${{ runner.temp }}/sheetjs-test-files.zip
- key: sheetjs-corpus-a786d4f1a80adf9447997b6f3b30b2593c776c27e0b075e3971627c17205f220
- - if: steps.archive.outputs.cache-hit != 'true'
- shell: bash
+ - shell: bash
run: curl --fail --location --retry 3 --max-time 300 https://test-files.sheetjs.com/test_files.zip -o "$RUNNER_TEMP/sheetjs-test-files.zip"
- shell: bash
run: |
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4d00bad8..69105aea 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -34,10 +34,11 @@ jobs:
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: ${{ matrix.node }}
- cache: npm
+ package-manager-cache: false
- run: npm ci --ignore-scripts
- uses: ./.github/actions/corpus
- run: make all
+ - run: npm run test:tooling
- run: npm run test:security
- run: npm run test:table-styles
- run: npm run test:cfb-minifat
@@ -62,7 +63,7 @@ jobs:
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
- cache: npm
+ package-manager-cache: false
- run: npm ci --ignore-scripts
- uses: ./.github/actions/corpus
- run: make all
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 3deb9d40..02865857 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -39,7 +39,7 @@ jobs:
with:
node-version: 24
registry-url: https://registry.npmjs.org
- cache: npm
+ package-manager-cache: false
- run: npm ci --ignore-scripts
- run: node --test .github/scripts/publish-npm.test.mjs
- run: npm run test:security
@@ -63,6 +63,7 @@ jobs:
node .github/scripts/publish-npm.mjs
fi
- name: Preserve the exact verified tarball
+ if: github.event_name == 'release' || inputs.dry_run == false
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml
index 02e67002..26e578a5 100644
--- a/.github/workflows/rebase.yml
+++ b/.github/workflows/rebase.yml
@@ -2,14 +2,26 @@ name: Automatic Rebase
on: [pull_request_target]
+permissions:
+ contents: read
+
jobs:
_:
name: "Automatic Rebase"
runs-on: ubuntu-latest
+ timeout-minutes: 5
steps:
- - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- - uses: ljharb/rebase@c6bd0a72b14dfaf76ad6a070029c8b4592d03eea
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - name: Read the branch relationship without rewriting a PR
env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ PR_HEAD: ${{ github.event.pull_request.head.sha }}
+ PR_BASE: ${{ github.event.pull_request.base.sha }}
+ run: |
+ node -e 'for (const name of ["PR_HEAD", "PR_BASE"]) { if (!/^[a-f0-9]{40}$/.test(process.env[name] || "")) throw new Error("Invalid PR commit identity"); }'
+ git fetch --no-tags origin "$PR_HEAD" "$PR_BASE"
+ git merge-base "$PR_BASE" "$PR_HEAD"
+ git rev-list --left-right --count "$PR_BASE...$PR_HEAD"
diff --git a/.github/workflows/require-allow-edits.yml b/.github/workflows/require-allow-edits.yml
index 9ae6992d..c457b218 100644
--- a/.github/workflows/require-allow-edits.yml
+++ b/.github/workflows/require-allow-edits.yml
@@ -2,11 +2,15 @@ name: Require “Allow Edits”
on: [pull_request_target]
+permissions:
+ contents: read
+
jobs:
_:
name: "Require “Allow Edits”"
runs-on: ubuntu-latest
+ timeout-minutes: 5
steps:
- uses: ljharb/require-allow-edits@13f90bc8cc5de000f2b44a0e2c3a11d108e8cd9f
diff --git a/.github/workflows/security-regression.yml b/.github/workflows/security-regression.yml
index e312a19b..efe32d1b 100644
--- a/.github/workflows/security-regression.yml
+++ b/.github/workflows/security-regression.yml
@@ -40,8 +40,10 @@ jobs:
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: 22
+ package-manager-cache: false
- run: npm ci --ignore-scripts
- run: npm audit --audit-level=low
+ - run: npm run test:tooling
- run: npm run test:security
- run: npm run test:table-styles
- run: make all
diff --git a/bin/xlsx.njs b/bin/xlsx.njs
index 13c8a183..f74227a8 100755
--- a/bin/xlsx.njs
+++ b/bin/xlsx.njs
@@ -1,6 +1,5 @@
#!/usr/bin/env node
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
-/* eslint-env node */
/* vim: set ts=2 ft=javascript: */
var n = "xlsx";
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 00000000..3d403e0f
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,28 @@
+import { readFileSync } from 'node:fs'
+import { FlatCompat } from '@eslint/eslintrc'
+import json from 'eslint-plugin-json'
+
+const compat = new FlatCompat({
+ baseDirectory: import.meta.dirname,
+})
+
+// The project keeps its original ES3 rule policy while using current ESLint.
+// .eslintrc explicitly retains the previous recommended rules and overrides.
+export default [
+ { ignores: ['**/xlsx.js'] },
+ ...compat.config(
+ JSON.parse(readFileSync(new URL('.eslintrc', import.meta.url), 'utf8')),
+ ),
+ {
+ files: ['**/*.{js,njs,json,html,htm}'],
+ languageOptions: { sourceType: 'script', globals: { JSON: 'readonly' } },
+ },
+ ...compat.config({ env: { node: true } })
+ .map(config => ({ ...config, files: ['bin/**/*.njs'] })),
+ ...compat.config({ env: { browser: true } })
+ .map(config => ({ ...config, files: ['**/*.{html,htm}'] })),
+ {
+ files: ['**/*.json'],
+ ...json.configs.recommended,
+ },
+]
diff --git a/index.html b/index.html
index ea19448a..b292de85 100644
--- a/index.html
+++ b/index.html
@@ -62,7 +62,6 @@
'), [])
+ assert.deepEqual(await messages(`probe.${extension}`, ''), [])
+ assert.ok((await messages(`probe.${extension}`, ''))
+ .some(message => message.ruleId === 'no-undef'))
+ }
+})
+
+test('the generated CJS bundle retains its existing exclusion', async () => {
+ assert.equal(await eslint.isPathIgnored('xlsx.js'), true)
+})
From e329118afcad0a116177d0e8df1d05ad1c3414a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B0=8F=E7=88=AC=E7=9A=84=E8=80=81=E7=B2=89=E4=B8=9D?=
<727842003@qq.com>
Date: Sun, 11 Oct 2026 14:08:18 +0800
Subject: [PATCH 2/2] ci: keep maintenance configuration and regression sources
reviewable
---
.gitattributes | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.gitattributes b/.gitattributes
index fc04ca62..9a0ffd20 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -17,3 +17,5 @@ tests/fixtures.js linguist-generated=true binary
test.mjs lingust-generated=false binary=false text eol=lf
.github/scripts/*.mjs linguist-generated=false !binary text diff merge eol=lf
+eslint.config.mjs linguist-generated=false !binary text diff merge eol=lf
+tests/*.mjs linguist-generated=false !binary text diff merge eol=lf