diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..455a07b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,25 @@ +version: 2 +updates: + # VS Code extension JavaScript/TypeScript toolchain. + - package-ecosystem: npm + directory: /vscode-extension + schedule: + interval: weekly + open-pull-requests-limit: 5 + groups: + dev-dependencies: + dependency-type: development + + # Python build-time deps used by the keyword-index generator. + - package-ecosystem: pip + directory: /scripts + schedule: + interval: weekly + open-pull-requests-limit: 3 + + # CI actions — keep SHA pins fresh as upstream tags advance. + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 diff --git a/.github/workflows/build-vsix.yml b/.github/workflows/build-vsix.yml index 102ad8e..2044770 100644 --- a/.github/workflows/build-vsix.yml +++ b/.github/workflows/build-vsix.yml @@ -8,17 +8,21 @@ on: branches: [main] workflow_dispatch: +# Default least-privilege token scope; jobs that need more elevate explicitly. +permissions: + contents: read + jobs: build-index: runs-on: ubuntu-latest steps: - name: Checkout (with submodule) - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: submodules: recursive - name: Setup Python - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: python-version: '3.12' cache: pip @@ -39,7 +43,7 @@ jobs: --compact vscode-extension/data/keyword_index_compact.json - name: Upload keyword index - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: keyword-index path: vscode-extension/data/keyword_index_compact.json @@ -56,17 +60,17 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: '24' cache: npm cache-dependency-path: vscode-extension/package-lock.json - name: Download freshly built keyword index - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: name: keyword-index path: vscode-extension/data @@ -81,10 +85,10 @@ jobs: run: npm run compile - name: Package VSIX - run: npx --yes @vscode/vsce package + run: npx --yes @vscode/vsce@3.9.1 package - name: Upload VSIX artifact - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: opm-flow-editor-support-vsix path: vscode-extension/opm-flow-editor-support-*.vsix @@ -92,7 +96,7 @@ jobs: - name: Attach VSIX to release if: startsWith(github.ref, 'refs/tags/v') - uses: softprops/action-gh-release@v3 + uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3 with: files: vscode-extension/opm-flow-editor-support-*.vsix @@ -102,12 +106,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: '24' - name: Download VSIX - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: name: opm-flow-editor-support-vsix path: . @@ -115,7 +119,7 @@ jobs: - name: Publish to VS Code Marketplace env: VSCE_PAT: ${{ secrets.VSCE_PAT }} - run: npx --yes @vscode/vsce publish --packagePath opm-flow-editor-support-*.vsix --pat "$VSCE_PAT" + run: npx --yes @vscode/vsce@3.9.1 publish --packagePath opm-flow-editor-support-*.vsix --pat "$VSCE_PAT" # Disabled until Open VSX account + OVSX_PAT secret are set up. # To re-enable: change `if: false` back to `if: startsWith(github.ref, 'refs/tags/v')`. @@ -125,12 +129,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: '24' - name: Download VSIX - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: name: opm-flow-editor-support-vsix path: . @@ -138,4 +142,4 @@ jobs: - name: Publish to Open VSX env: OVSX_PAT: ${{ secrets.OVSX_PAT }} - run: npx --yes ovsx publish opm-flow-editor-support-*.vsix -p "$OVSX_PAT" + run: npx --yes ovsx@0.10.12 publish opm-flow-editor-support-*.vsix -p "$OVSX_PAT" diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..0ff369c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,42 @@ +# Security Policy + +## Supported versions + +Only the latest released version of the OPM Flow Editor Support VS Code +extension receives security updates. Older versions are not patched. + +## Reporting a vulnerability + +If you believe you have found a security vulnerability in this extension, +please report it privately rather than opening a public issue. + +Use GitHub's +[private vulnerability reporting](https://github.com/OPM/opm-flow-editor-support/security/advisories/new) +to route the report directly to the maintainers. Please include: + +- A description of the issue and its impact. +- Steps to reproduce, ideally including a minimal deck file or + configuration that triggers the behaviour. +- The extension version (`Extensions: Show Installed Extensions` in + VS Code) and your VS Code version. + +You should receive an acknowledgement within a few business days. We will +work with you on a fix and coordinate a disclosure timeline; please give +us a reasonable window to release a patched version before any public +disclosure. + +## Scope + +In scope: + +- The published `magne-sjaastad.opm-flow-editor-support` VS Code extension. +- The build / packaging pipeline in `.github/workflows/build-vsix.yml`. +- Helper scripts in `scripts/` that produce the bundled keyword index. + +Out of scope: + +- Vulnerabilities in OPM Flow itself, the OPM reference manual, or other + upstream OPM projects — please report those to the relevant + [OPM repository](https://github.com/OPM). +- Issues that require an already-compromised developer machine or an + attacker-controlled VS Code installation. diff --git a/vscode-extension/src/extension.ts b/vscode-extension/src/extension.ts index 993af1c..3e23c48 100644 --- a/vscode-extension/src/extension.ts +++ b/vscode-extension/src/extension.ts @@ -200,7 +200,12 @@ function resolveKeyword(index: KeywordIndex, kw: string): KeywordEntry | undefin // --------------------------------------------------------------------------- function escHtml(s: string): string { - return s.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); + return s + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); } function paramTypeLabel(p: Parameter): string { @@ -327,7 +332,7 @@ function buildDocsHtml( ? ' class="highlight"' : ''; const dataRecord = p.record !== undefined ? ` data-record="${escHtml(String(p.record))}"` : ''; - return `${p.index}${escHtml(p.name)}${escHtml(p.description)}${typeCell}${unitCells}${defaultCell}`; + return `${escHtml(String(p.index))}${escHtml(p.name)}${escHtml(p.description)}${typeCell}${unitCells}${defaultCell}`; }; const tableHead = `No.NameDescription${typeCol}${unitCols}${defaultCol}`; @@ -422,7 +427,10 @@ class DocsViewProvider implements vscode.WebviewViewProvider { resolveWebviewView(view: vscode.WebviewView): void { this._view = view; - view.webview.options = { enableScripts: true }; + // The docs panel renders only inline HTML/CSS/JS that we build here, so + // it never needs to load files from disk. Drop `localResourceRoots` to + // an empty list to deny the webview any filesystem access. + view.webview.options = { enableScripts: true, localResourceRoots: [] }; view.webview.html = buildDocsHtml(null, null, getDocColumns()); this._currentEntry = undefined; this._currentParam = undefined; @@ -469,7 +477,9 @@ function buildKeywordHover( isExcluded?: boolean, ): vscode.MarkdownString { const md = new vscode.MarkdownString(); - md.isTrusted = true; + // `supportHtml` is enough for the inline notices below. + // `isTrusted` would additionally permit `command:` links to execute, which + // these hovers never use — keep it off as defense in depth. md.supportHtml = true; if ( @@ -499,7 +509,7 @@ function buildKeywordHover( function buildParameterHover(entry: KeywordEntry, param: Parameter): vscode.MarkdownString { const md = new vscode.MarkdownString(); - md.isTrusted = true; + // No HTML or command links needed here — pure markdown is sufficient. md.appendMarkdown(`**\`${entry.name}\` — parameter ${param.index}: \`${param.name}\`**\n\n`); md.appendMarkdown(`${param.description}\n\n`); const cols = getDocColumns();