diff --git a/.github/linters/actionlint.yaml b/.github/actionlint.yaml similarity index 100% rename from .github/linters/actionlint.yaml rename to .github/actionlint.yaml diff --git a/.github/linters/.markdownlint.js b/.github/linters/.markdownlint.js deleted file mode 100644 index 697f383..0000000 --- a/.github/linters/.markdownlint.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - "config": { - "default": true, - "blanks-around-lists": false, - "no-inline-html": false, - "no-bare-urls": false, - } -} diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 1041b0c..3489ebd 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -2,8 +2,6 @@ name: "Lint Code Base" 'on': - push: - branches-ignore: [main] pull_request: branches: [main] workflow_dispatch: @@ -19,45 +17,35 @@ jobs: timeout-minutes: 10 steps: - # Checkout the code base - name: "Checkout Code" uses: actions/checkout@v6 - with: - # Full git history needed for `super-linter` changed files list - fetch-depth: 0 - # Setup Node.js - name: "Setup Node.js" uses: actions/setup-node@v6 with: node-version: '22.x' - # Cache node_modules for ESLint installation - - name: "Cache npm dependencies" + - name: "Cache npm downloads" uses: actions/cache@v5 with: - path: node_modules - key: npm-${{ runner.os }}-eslint - restore-keys: | - npm-${{ runner.os }}- - - # Install ESLint & plugin (not in package.json; zero dependencies) - - name: Install ESLint Plugins - run: npm install --no-save --engine-strict=false eslint eslint-plugin-n - - # Run Linter against code base - - name: Super-linter - uses: super-linter/super-linter/slim@v8 - env: - ACTIONS_RUNNER_DEBUG: false - DEFAULT_BRANCH: main - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - LOG_LEVEL: NOTICE - SUPPRESS_POSSUM: true - VALIDATE_ALL_CODEBASE: false - VALIDATE_GITHUB_ACTIONS: true - VALIDATE_JAVASCRIPT_ES: true - VALIDATE_JSON: true - VALIDATE_JSONC: true - VALIDATE_MARKDOWN: true - VALIDATE_YAML: true + path: ~/.npm + key: npm-${{ runner.os }}-${{ hashFiles('.github/workflows/linter.yml') }} + + - name: "Install lint tools" + run: npm install --no-save --engine-strict=false eslint @eslint/js eslint-plugin-n markdownlint-cli2 + + - name: "Lint JavaScript (ESLint)" + run: npx eslint . + + - name: "Lint Markdown" + run: npx markdownlint-cli2 "**/*.md" "#node_modules" + + - name: "Lint YAML" + run: pip install --quiet yamllint && yamllint . + + - name: "Lint JSON" + run: | + find . -name '*.json' \ + -not -path './node_modules/*' \ + -not -path './.git/*' \ + -print0 | xargs -0 -I{} node -e "JSON.parse(require('fs').readFileSync('{}','utf8'))" \ No newline at end of file diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..9afc555 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,6 @@ +{ + "default": true, + "blanks-around-lists": false, + "no-inline-html": false, + "no-bare-urls": false +} diff --git a/.github/linters/.yaml-lint.yml b/.yamllint.yml similarity index 100% rename from .github/linters/.yaml-lint.yml rename to .yamllint.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cc6b9a..f5548d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 1.19.0 -- Add standalone CLI (`bin/js2uri.js`) using only Node.js built-ins (`fs`, `path`) +- Add standalone CLI (`bin/js2uri.js`) using only Node.js built-ins (`fs`, + `path`) - Export helpers as `main` entry point (`tasks/js2uriHelpers.js`) - Mark `grunt` peerDependency as optional via `peerDependenciesMeta` -- Add `npm overrides` to force `minimatch@3.1.5`, fixing 2 high-severity ReDoS vulnerabilities (GHSA-3ppc-4f35-3m26, GHSA-7r86-cg39-jmmj) -- Fix `files` field: `"tests/"` → `"bin/"` (test dir was misnamed and tests shouldn't publish) +- Add `npm overrides` to force `minimatch@3.1.5`, fixing 2 high-severity ReDoS + vulnerabilities (GHSA-3ppc-4f35-3m26, GHSA-7r86-cg39-jmmj) +- Fix `files` field: `"tests/"` → `"bin/"` (test dir was misnamed and tests + shouldn't publish) - Update description and keywords to reflect CLI/API/grunt usage - Require Node.js >=22.22.0 @@ -55,8 +58,8 @@ simplifies maintenance. - **Minimum npm version:** `>=10.9.0` (previously `>=10.8.2`) - **Dropped support for:** Node.js 20.x and 21.x - #### Test Framework Migration + - **Removed:** `grunt-contrib-nodeunit` (replaced with Node.js built-in test runner) - **New test command:** `node --test test/js2uri*.js` diff --git a/README.md b/README.md index 0cf9a1f..0416459 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,14 @@ use the grunt plugin. Tests use the Node.js built-in test runner. Version 1.19.0 Add standalone CLI script, make grunt peerDependency optional -Version 1.18.2 harden build & ci for greater resistance against supply chain attack +Version 1.18.2 harden build & ci for greater resistance against supply chain +attack -Version 1.18.1 improved supply security, refined .npmrc, & reduced published package size +Version 1.18.1 improved supply security, refined .npmrc, & reduced published +package size -Version 1.14.4 drops support & testing for node < 20.19.5 (tests node 25.x & drops 23.x) +Version 1.14.4 drops support & testing for node < 20.19.5 (tests node 25.x & +drops 23.x) Version 1.14.0 drops support & testing for node < 18.20.0 @@ -233,9 +236,12 @@ code. ## Release History -1.19.0: add standalone CLI (`bin/js2uri.js`), export helpers as `main`, mark grunt as optional peerDependency, add npm overrides for minimatch 3.1.5 to fix ReDoS vulnerabilities +1.19.0: add standalone CLI (`bin/js2uri.js`), export helpers as `main`, mark +grunt as optional peerDependency, add npm overrides for minimatch 3.1.5 to fix +ReDoS vulnerabilities -1.18.0: requires npm >=11.5.1; migrates to npm trusted publishing with OIDC (eliminates token management) +1.18.0: requires npm >=11.5.1; migrates to npm trusted publishing with OIDC +(eliminates token management) 1.17.0: drops support for node < 22.12 and begins "zero dependency" approach with new CI @@ -243,9 +249,11 @@ with new CI 1.16.0: drops support for node < 22.12 and begins "zero dependency" approach with new CI -1.15.4: update test coverage to node 25.x, update to node >=20.19.5 & bump version, update README & regenerate package-lock.json +1.15.4: update test coverage to node 25.x, update to node >=20.19.5 & bump +version, update README & regenerate package-lock.json -1.15.3: no functional changes; update ci actions for node 24.x, bump version, update lockfile, republish +1.15.3: no functional changes; update ci actions for node 24.x, bump version, +update lockfile, republish 1.15.1: no functional change; integrate cspell for use with git pre-push hook, fix typos, update lockfile diff --git a/SECURITY.md b/SECURITY.md index cf4fdb2..6a66dcf 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,8 @@ ## Supported Versions -The following versions of js2uri are currently supported with security updates: +The following versions of js2uri are currently supported with security +updates: | Version | Supported | | ------- | ------------------ | @@ -17,9 +18,12 @@ The following versions of js2uri are currently supported with security updates: - Reporter receives recognition for discovery - Allows collaborative fix development before public announcement -2. **Alternative:** If you cannot use GitHub Security Advisories, create a private issue or contact the maintainer directly (see package.json for contact info) +2. **Alternative:** If you cannot use GitHub Security Advisories, create a +private issue or contact the maintainer directly (see package.json for contact +info) -**Please do not report security vulnerabilities via public GitHub issues** as this may put users at risk before a fix is available. +**Please do not report security vulnerabilities via public GitHub issues** as +this may put users at risk before a fix is available. ### What to Include @@ -40,27 +44,35 @@ When reporting a vulnerability, please include: ### Access & Publishing -- **2FA Required:** All package maintainers must enable two-factor authentication on their npm accounts -- **Automated Publishing:** Packages are published from GitHub Actions using OIDC trusted publishing +- **2FA Required:** All package maintainers must enable two-factor + authentication on their npm accounts +- **Automated Publishing:** Packages are published from GitHub Actions using + OIDC trusted publishing - Publishing triggered via GitHub Releases (on: release) - Uses OpenID Connect (OIDC) authentication - no long-lived tokens required - Provenance attestation provides cryptographic proof of build origin - Published packages can be verified at: `npm view js2uri@ --json` - - **Zero Dependencies:** No supply chain to audit - eliminates transitive dependency vulnerabilities + - **Zero Dependencies:** No supply chain to audit - eliminates transitive + dependency vulnerabilities ### Code Integrity - **Signed Commits:** All commits to the main branch must be GPG signed - **Code Review:** All changes require review and approval before merging (via CODEOWNERS) -- **Dependencies:** Zero production dependencies eliminate dependency vulnerabilities +- **Dependencies:** Zero production dependencies eliminate dependency + vulnerabilities - **Dependency Monitoring:** Dependabot monitors for future dependency issues -- **Lockfile Protection:** `npm ci` validates package-lock.json integrity (fails if corrupted or mismatched) +- **Lockfile Protection:** `npm ci` validates package-lock.json integrity + (fails if corrupted or mismatched) ### Supply Chain Hardening -- **Lifecycle Scripts Disabled:** `.npmrc` configured with `ignore-scripts=true` to block malicious postinstall/preinstall scripts from dependencies -- **Engine Enforcement:** `engine-strict=true` ensures consistent Node.js versions across environments -- **Registry Security:** HTTPS registry enforced via `.npmrc`, no fallback to insecure HTTP +- **Lifecycle Scripts Disabled:** `.npmrc` configured with `ignore-scripts=true` + to block malicious postinstall/preinstall scripts from dependencies +- **Engine Enforcement:** `engine-strict=true` ensures consistent Node.js + versions across environments +- **Registry Security:** HTTPS registry enforced via `.npmrc`, no fallback to + insecure HTTP ## Branch Protection Rules @@ -82,7 +94,7 @@ The main branch has the following protections enabled: ### Branch Restrictions -- **Admin Enforcement:** Branch protection rules apply equally to administrators +- **Admin Enforcement:** Branch protection rules apply equally to admins - **Force Push Protection:** Force pushes disabled - **Deletion Protection:** Branch deletions disabled @@ -91,16 +103,19 @@ The main branch has the following protections enabled: The following GitHub security features are enabled: - **Vulnerability Alerts:** Dependabot alerts for known vulnerabilities -- **Automated Security Updates:** Dependabot automatically creates PRs for security fixes +- **Automated Security Updates:** Dependabot automatically creates PRs for + security fixes - **Secret Scanning:** Detects exposed credentials and tokens - **Push Protection:** Blocks commits containing secrets - **Private Vulnerability Reporting:** Via GitHub Security Advisories ### Workflow Permissions -- **Least Privilege:** CI workflows use minimal permissions (`contents: read`) -- **Scoped Publishing:** Publish workflow only grants `contents: write` and `id-token: write` -- **Repository Restriction:** Publishing only runs from `mobilemind/js2uri`, preventing fork-based attacks +- **Least Privilege:** CI workflows use minimal permissions (read) +- **Scoped Publishing:** Publish workflow only grants `contents: write` and + `id-token: write` +- **Repository Restriction:** Publishing only runs from `mobilemind/js2uri`, + preventing fork-based attacks ## Verification diff --git a/.github/linters/eslint.config.js b/eslint.config.js similarity index 98% rename from .github/linters/eslint.config.js rename to eslint.config.js index 9628bb5..72ffed6 100644 --- a/.github/linters/eslint.config.js +++ b/eslint.config.js @@ -4,7 +4,7 @@ const n = require("eslint-plugin-n"); module.exports = [ { - files: [".github/linters/eslint.config.js", "Gruntfile.js", "tasks/*.js", "test/*.js"], + files: ["eslint.config.js", "Gruntfile.js", "tasks/*.js", "test/*.js"], ignores: ["*.json", "node_modules/*", "web/*.js"], languageOptions: { ecmaVersion: "latest",