Skip to content

Commit

Permalink
Support go (#16)
Browse files Browse the repository at this point in the history
* Enable go via workspace detection
  • Loading branch information
101arrowz authored Aug 18, 2023
1 parent 026ba5b commit 0e761c1
Show file tree
Hide file tree
Showing 22 changed files with 2,033 additions and 1,011 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--disable-extensions",
// "--disable-extensions",
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
Expand Down
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"cSpell.words": [
"esbuild",
"socketsecurity"
]
],
"typescript.tsdk": "node_modules/typescript/lib"
}
1,138 changes: 497 additions & 641 deletions package-lock.json

Large diffs are not rendered by default.

19 changes: 15 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@
"workspaceContains:**/{*[rR][eE][qQ][uU][iI][rR][eE][mM][eE][nN][tT][sS].[tT][xX][tT],[rR][eE][qQ][uU][iI][rR][eE][mM][eE][nN][tT][sS]/*.[tT][xX][tT],[rR][eE][qQ][uU][iI][rR][eE][mM][eE][nN][tT][sS]-*.[tT][xX][tT],[rR][eE][qQ][uU][iI][rR][eE][mM][eE][nN][tT][sS].[fF][rR][oO][zZ][eE][nN]}",
"workspaceContains:**/[pP][yY][pP][rR][oO][jJ][eE][cC][tT].[tT][oO][mM][lL]",
"workspaceContains:**/[pP][iI][pP][fF][iI][lL][eE]",
"workspaceContains:**/[gG][oO].[mM][oO][dD]",
"workspaceContains:**/[gG][oO].[sS][uU][mM]",
"onLanguage:python",
"onLanguage:javascript"
"onLanguage:javascript",
"onLanguage:go"
],
"type": "commonjs",
"main": "./out/main.js",
Expand Down Expand Up @@ -103,6 +106,14 @@
"examples": [
"/usr/bin/python"
]
},
"socket-security.goExecutable": {
"order": 6,
"type": "string",
"description": "Path to a Go executable to use for Socket dependency analysis.",
"examples": [
"/usr/bin/go"
]
}
}
}
Expand All @@ -113,7 +124,7 @@
"publisher": "SocketSecurity",
"scripts": {
"vscode:prepublish": "npm run esbuild -- --minify",
"esbuild-base": "esbuild --bundle --external:vscode --outdir=out/ --platform=node --sourcemap",
"esbuild-base": "esbuild --bundle --external:vscode --loader:.wasm=binary --loader:.go=file --outdir=out/ --platform=node --sourcemap",
"esbuild": "npm run esbuild-base -- --format=cjs main=src/extension.ts",
"test-compile": "tsc -p ./",
"lint": "eslint \"src/**/*.ts\"",
Expand All @@ -123,6 +134,7 @@
"dependencies": {
"@babel/parser": "^7.20.7",
"@socketsecurity/config": "^2.0.0",
"@vscode/vsce": "^2.20.1",
"acorn-walk": "^8.2.0",
"antlr4": "^4.13.0",
"ast-types": "^0.14.2",
Expand All @@ -147,8 +159,7 @@
"esbuild": "^0.16.7",
"eslint": "^8.26.0",
"toml-eslint-parser": "^0.6.0",
"typescript": "^4.8.4",
"vsce": "^2.15.0"
"typescript": "^4.8.4"
},
"repository": {
"url": "https://github.com/SocketDev/vscode-socket-security"
Expand Down
77 changes: 77 additions & 0 deletions src/data/go/builtins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const goBuiltins = [
'archive/tar',
'archive/zip',
'bufio',
'bytes',
'compress/bzip2',
'compress/flate',
'compress/gzip',
'compress/lzw',
'compress/zlib',
'container/heap',
'container/list',
'container/ring',
'context',
'crypto',
'database/sql',
'debug/buildinfo',
'debug/dwarf',
'debug/elf',
'debug/gosym',
'debug/macho',
'debug/pe',
'debug/plan9obj',
'embed',
'encoding',
'errors',
'expvar',
'flag',
'fmt',
'go/ast',
'go/build',
'go/constant',
'go/doc',
'go/format',
'go/importer',
'go/internal/gccgoimporter',
'go/internal/gcimporter',
'go/internal/srcimporter',
'go/internal/typeparams',
'go/parser',
'go/printer',
'go/scanner',
'go/token',
'go/types',
'hash',
'html',
'image',
'index/suffixarray',
'internal',
'io',
'log',
'math',
'mime',
'net',
'os',
'path',
'plugin',
'reflect',
'regexp',
'runtime',
'sort',
'strconv',
'strings',
'sync',
'syscall',
'testing',
'text/scanner',
'text/tabwriter',
'text/template',
'time',
'unicode',
'unsafe'
]

export function isGoBuiltin (pkg: string) {
return goBuiltins.some(builtin => pkg === builtin || pkg.startsWith(builtin + '/'))
}
62 changes: 62 additions & 0 deletions src/data/go/executable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import * as vscode from 'vscode'
import { EXTENSION_PREFIX } from '../../util';

async function getGoExtension() {
const go = vscode.extensions.getExtension('golang.go');
if (go && !go.isActive) await go.activate();
return go?.exports;
}

export async function initGo(): Promise<vscode.Disposable> {
// in the future, do any needed init work with the golang.go extension instance here
return new vscode.Disposable(() => {});
}

const warned = new Set<string>();

export async function getGoExecutable(fileName?: string): Promise<string | void> {
// no executable in virtual workspace
if (vscode.workspace.workspaceFolders?.every(f => f.uri.scheme !== 'file')) return
const workspaceConfig = vscode.workspace.getConfiguration(EXTENSION_PREFIX);
const pathOverride = workspaceConfig.get<string>('goExecutable');
if (pathOverride) {
return Promise.resolve(vscode.workspace.fs.stat(vscode.Uri.file(pathOverride))).then(
st => {
if (st.type & vscode.FileType.File) return pathOverride;
throw new Error('not a file')
}
).catch(err => {
vscode.window.showErrorMessage(`Failed to find Go binary at '${pathOverride}'. Please update ${EXTENSION_PREFIX}.goExecutable.`)
})
}
const ext = await getGoExtension();
const cmd = await ext?.settings.getExecutionCommand(
'go',
fileName && vscode.Uri.file(fileName)
)
if (cmd) return cmd.binPath
const workspaceID = vscode.workspace.name ||
vscode.workspace.workspaceFolders?.map(f => f.uri.fsPath).join(',') ||
vscode.window.activeTextEditor?.document.uri.fsPath;
if (workspaceID) {
if (warned.has(workspaceID)) return;
warned.add(workspaceID);
}
const installGo = 'Install Go extension';
const configGo = 'Configure Go extension';
const setPath = `Configure Socket`;
vscode.window.showErrorMessage(
`Socket failed to find a Go installation; please ${ext ? 'install the Go toolchain with' : 'install'} the Go extension or set ${EXTENSION_PREFIX}.goExecutable.`,
ext ? configGo : installGo,
setPath
).then(async res => {
if (res === installGo) {
vscode.env.openExternal(vscode.Uri.parse('vscode:extension/golang.go'));
} else if (res === configGo) {
vscode.commands.executeCommand('go.tools.install');
} else if (res === setPath) {
await workspaceConfig.update('goExecutable', '', vscode.ConfigurationTarget.Global)
vscode.commands.executeCommand('workbench.action.openSettingsJson');
}
})
}
70 changes: 70 additions & 0 deletions src/data/go/find-imports.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package main

import (
"encoding/json"
"bufio"
"os"
"go/parser"
"go/token"
"strconv"
)

// Eventually maybe migrate to WASI with tinygo


type VSPosition struct {
Line int `json:"line"`
Character int `json:"character"`
}

type VSRange struct {
Start VSPosition `json:"start"`
End VSPosition `json:"end"`
}

type GoImport struct {
Name string `json:"name"`
Range VSRange `json:"range"`
}

func toVSPos(src token.Position) VSPosition {
// TODO: breaks on unicode but probably rare enough to not matter
return VSPosition { src.Line - 1, src.Column - 1, }
}

func main() {
reader := bufio.NewReader(os.Stdin)
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, "src.go", reader, parser.ImportsOnly)

if err != nil {
os.Stderr.Write([]byte(err.Error()))
os.Exit(1)
}

results := make([]GoImport, 0)

for _, imp := range file.Imports {
start := fset.Position(imp.Pos())
end := fset.Position(imp.End())
name, nameErr := strconv.Unquote(imp.Path.Value)

if nameErr != nil {
os.Stderr.Write([]byte(nameErr.Error()))
os.Exit(1)
}

results = append(results, GoImport {
name,
VSRange { toVSPos(start), toVSPos(end), },
})
}

result, encErr := json.Marshal(results)
if encErr != nil {
os.Stderr.Write([]byte(err.Error()))
os.Exit(1)
}

os.Stdout.Write(result)
}
55 changes: 55 additions & 0 deletions src/data/go/import-finder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import importFinder from './find-imports.go'

let cachedBin: Promise<string> | null = null
let lastBinPath: string | null = null

export async function generateNativeGoImportBinary (goBin: string) {
const [
childProcess,
path,
fs,
os
] = await Promise.all([
import('node:child_process'),
import('node:path'),
import('node:fs/promises'),
import('node:os')
])
if (cachedBin && lastBinPath === goBin) {
const bin = await cachedBin.catch(() => null)
if (bin) {
const valid = await fs.lstat(bin).then(f => {
return f.isFile()
}, err => {
if (err && (typeof err as { code?: unknown }).code === 'ENOENT') {
return false
}
throw err
})
if (valid) return bin
}
}
lastBinPath = goBin
cachedBin = (async () => {
const outBin = path.join(await fs.mkdtemp(path.join(os.tmpdir(), 'socket-')), 'go-import-parser')
const build = childProcess.spawn(goBin, ['build', '-o', outBin, importFinder], {
cwd: __dirname
})

const exitCode = await new Promise<number | null>((resolve, reject) => {
build.once('exit', resolve)
build.once('error', reject)
setTimeout(() => reject(new Error('timeout')), 3000)
})

if (exitCode) {
throw new Error(`failed to build with code ${exitCode}`)
}

return outBin
})()

return cachedBin

}

Loading

0 comments on commit 0e761c1

Please sign in to comment.