-
-
Notifications
You must be signed in to change notification settings - Fork 0
ci: add PR build/typecheck/test workflow + fix latent type errors #414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| name: CI | ||
|
|
||
| # Runs on every PR to main and on pushes to main, so type errors and test | ||
| # failures are caught before merge (release.yml only runs on version tags). | ||
| on: | ||
| pull_request: | ||
| branches: [main] | ||
| push: | ||
| branches: [main] | ||
|
|
||
| concurrency: | ||
| group: ci-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| build-typecheck-test: | ||
| name: Build, typecheck & test | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pin actions to commit hashes per security policy. The workflow uses version tags ( 🔒 Guidance for pinning to commit hashesReplace version tags with full commit SHA hashes. For example: - - uses: actions/checkout@v4
+ - uses: actions/checkout@<commit-sha> # v4.x.x
- - uses: actions/setup-node@v4
+ - uses: actions/setup-node@<commit-sha> # v4.x.xLook up the latest commit hashes for the v4 releases of these actions in their respective repositories, and add a comment with the version number for future reference. Also applies to: 22-22 🧰 Tools🪛 zizmor (1.25.2)[warning] 20-20: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) [error] 20-20: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) 🤖 Prompt for AI Agents |
||
|
|
||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 22 | ||
| cache: npm | ||
|
|
||
| - name: Install dependencies | ||
| run: npm ci | ||
|
|
||
| - name: Build extension, worker & WASM | ||
| run: node scripts/build.mjs | ||
|
|
||
| - name: Typecheck (src + tests) | ||
| run: npx tsc --noEmit -p tsconfig.json | ||
|
|
||
| - name: Unit tests | ||
| run: npm test | ||
Check warningCode scanning / CodeQL Workflow does not contain permissions Medium
Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
|
||
|
Comment on lines
+17
to
+37
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -5,7 +5,7 @@ import * as path from 'path'; | |||||
|
|
||||||
| async function runBenchmark() { | ||||||
| const bundle = await createNativeDatabaseConnection(vscode.Uri.file(process.cwd())); | ||||||
| const loadResult = await bundle.loadDatabase({ buffer: new Uint8Array() }); | ||||||
| const loadResult = await (bundle as any).loadDatabase({ buffer: new Uint8Array() }); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Instead of casting to
Suggested change
|
||||||
| const db = loadResult.databaseOps; | ||||||
|
|
||||||
| // create table | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -34,7 +34,7 @@ async function runBenchmark() { | |||||
|
|
||||||
| try { | ||||||
| const wasmBinary = fs.readFileSync(path.resolve(__dirname, '../../node_modules/sql.js/dist/sql-wasm.wasm')); | ||||||
| const engineResult = await createDatabaseEngine({ wasmBinary }); | ||||||
| const engineResult = await createDatabaseEngine({ wasmBinary } as any); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of casting the configuration object to
Suggested change
|
||||||
| const db = engineResult.operations as WasmDatabaseEngine; | ||||||
|
|
||||||
| const numIndexes = 50; | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -48,10 +48,10 @@ async function runBenchmark() { | |||||||||||||||||||
| const start = performance.now(); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // 1. Undo (Adds columns back) | ||||||||||||||||||||
| await databaseOps.undoModification(mod); | ||||||||||||||||||||
| await databaseOps.undoModification(mod as any); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // 2. Redo (Drops columns again) | ||||||||||||||||||||
| await databaseOps.redoModification(mod); | ||||||||||||||||||||
| await databaseOps.redoModification(mod as any); | ||||||||||||||||||||
|
Comment on lines
+51
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Instead of casting
Suggested change
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| const end = performance.now(); | ||||||||||||||||||||
| console.log(`Undo + Redo took ${(end - start).toFixed(2)}ms`); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -26,7 +26,7 @@ describe('HostBridge', () => { | |||||
| await bridge.saveFile('../../../etc/passwd', new Uint8Array([1, 2, 3])); | ||||||
|
|
||||||
| assert.strictEqual(showSaveDialogMock.mock.callCount(), 1); | ||||||
| const args = showSaveDialogMock.mock.calls[0].arguments[0]; | ||||||
| const args = showSaveDialogMock.mock.calls[0].arguments[0] as any; | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of casting
Suggested change
|
||||||
| // The defaultUri path should end with the base name 'passwd', not the traversed path | ||||||
| assert.ok(args.defaultUri.path.endsWith('/dbDir/passwd'), `Expected safe path, got ${args.defaultUri.path}`); | ||||||
|
|
||||||
|
|
@@ -135,7 +135,7 @@ describe('HostBridge', () => { | |||||
| }; | ||||||
| const mockProvider = { webviews: new Map(), context: {} }; | ||||||
| const bridge = new HostBridge(mockProvider as any, mockDocument as any); | ||||||
| bridge.ensureDatabaseInitialized = () => dbOps as any; | ||||||
| (bridge as any).ensureDatabaseInitialized = () => dbOps as any; | ||||||
|
|
||||||
| await bridge.deleteRows('table1', [1]); | ||||||
|
|
||||||
|
|
@@ -162,7 +162,7 @@ describe('HostBridge', () => { | |||||
| }; | ||||||
| const mockProvider = { webviews: new Map(), context: {} }; | ||||||
| const bridge = new HostBridge(mockProvider as any, mockDocument as any); | ||||||
| bridge.ensureDatabaseInitialized = () => dbOps as any; | ||||||
| (bridge as any).ensureDatabaseInitialized = () => dbOps as any; | ||||||
|
|
||||||
| await bridge.deleteColumns('table1', ['col1']); | ||||||
|
|
||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -52,7 +52,7 @@ if (!mockVscode.extensions) { | |||||
| (mockVscode.workspace as any).registerFileSystemProvider = () => ({ dispose: () => {} }); | ||||||
| (mockVscode.window as any).createOutputChannel = () => ({ dispose: () => {} }); | ||||||
| (mockVscode.window as any).registerCustomEditorProvider = () => ({ dispose: () => {} }); | ||||||
| (mockVscode.ConfigurationTarget as any) = { Global: 1 }; | ||||||
| (mockVscode as any).ConfigurationTarget = { Global: 1 }; | ||||||
| (mockVscode.workspace as any).getConfiguration = () => { | ||||||
| return { | ||||||
| get: () => ({}), | ||||||
|
|
@@ -170,7 +170,7 @@ describe('main.ts', () => { | |||||
| await main.activate(mockContext); | ||||||
|
|
||||||
| assert.strictEqual(configUpdateMock.mock.calls.length, 1); | ||||||
| const callArgs = configUpdateMock.mock.calls[0].arguments; | ||||||
| const callArgs = configUpdateMock.mock.calls[0].arguments as any[]; | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of casting
Suggested change
|
||||||
| assert.strictEqual(callArgs[0], 'patterns'); | ||||||
| // The actual value in codebase may be different, we should check it | ||||||
| assert.ok(callArgs[1]['*.sqlite']); | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -244,7 +244,7 @@ describe('WasmDatabaseEngine', () => { | |||||
| } | ||||||
| } as unknown as Database; | ||||||
|
|
||||||
| const engine = new WasmDatabaseEngine(mockDb, 5000); | ||||||
| const engine = new WasmDatabaseEngine(mockDb as any, 5000); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of casting
Suggested change
|
||||||
|
|
||||||
| const consoleWarnOrig = console.warn; | ||||||
| let warnedMessage = ''; | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -87,8 +87,8 @@ describe('workerFactory error path tests', () => { | |||||||||||||||||||||||||||||||||||||||||
| mockVscode.workspace.fs = { | ||||||||||||||||||||||||||||||||||||||||||
| readFile: async () => new Uint8Array(), | ||||||||||||||||||||||||||||||||||||||||||
| stat: async () => ({ size: 0 }) | ||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||
| mockVscode.Uri.joinPath = () => ({ scheme: 'file', fsPath: '/test/path/assets/sqlite3.wasm' }); | ||||||||||||||||||||||||||||||||||||||||||
| } as any; | ||||||||||||||||||||||||||||||||||||||||||
| (mockVscode.Uri as any).joinPath = () => ({ scheme: 'file', fsPath: '/test/path/assets/sqlite3.wasm' }); | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
87
to
+91
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial | 💤 Low value Consider using The coding guidelines recommend using As per coding guidelines, "Use ♻️ Proposed refactor using Object.defineProperty- mockVscode.workspace.fs = {
- readFile: async () => new Uint8Array(),
- stat: async () => ({ size: 0 })
- } as any;
- (mockVscode.Uri as any).joinPath = () => ({ scheme: 'file', fsPath: '/test/path/assets/sqlite3.wasm' });
+ Object.defineProperty(mockVscode.workspace, 'fs', {
+ value: {
+ readFile: async () => new Uint8Array(),
+ stat: async () => ({ size: 0 })
+ },
+ writable: true,
+ configurable: true
+ });
+ Object.defineProperty(mockVscode.Uri, 'joinPath', {
+ value: () => ({ scheme: 'file', fsPath: '/test/path/assets/sqlite3.wasm' }),
+ writable: true,
+ configurable: true
+ });📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| afterEach(() => { | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add explicit permissions block to follow least privilege.
The workflow inherits default GITHUB_TOKEN permissions, which are overly broad. This workflow only needs read access to check out the repository.
🔒 Proposed fix to add minimal permissions
📝 Committable suggestion
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 1-38: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block
(excessive-permissions)
🤖 Prompt for AI Agents