Skip to content

Commit 5ba0e92

Browse files
author
Aaron Goodfellow
committed
feat(PI-4808): initial commit - use nowsecure-ci binary for extension
1 parent 9e5b52c commit 5ba0e92

File tree

10 files changed

+3983
-1
lines changed

10 files changed

+3983
-1
lines changed

.gitignore

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
lerna-debug.log*
8+
9+
# Diagnostic reports (https://nodejs.org/api/report.html)
10+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11+
12+
# Runtime data
13+
pids
14+
*.pid
15+
*.seed
16+
*.pid.lock
17+
18+
# Directory for instrumented libs generated by jscoverage/JSCover
19+
lib-cov
20+
21+
# Coverage directory used by tools like istanbul
22+
coverage
23+
*.lcov
24+
25+
# nyc test coverage
26+
.nyc_output
27+
28+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29+
.grunt
30+
31+
# Bower dependency directory (https://bower.io/)
32+
bower_components
33+
34+
# node-waf configuration
35+
.lock-wscript
36+
37+
# Compiled binary addons (https://nodejs.org/api/addons.html)
38+
build/Release
39+
40+
# Dependency directories
41+
node_modules/
42+
jspm_packages/
43+
44+
# Snowpack dependency directory (https://snowpack.dev/)
45+
web_modules/
46+
47+
# TypeScript cache
48+
*.tsbuildinfo
49+
50+
# Optional npm cache directory
51+
.npm
52+
53+
# Optional eslint cache
54+
.eslintcache
55+
56+
# Optional stylelint cache
57+
.stylelintcache
58+
59+
# Optional REPL history
60+
.node_repl_history
61+
62+
# Output of 'npm pack'
63+
*.tgz
64+
65+
# Yarn Integrity file
66+
.yarn-integrity
67+
68+
# dotenv environment variable files
69+
.env
70+
.env.*
71+
!.env.example
72+
73+
# parcel-bundler cache (https://parceljs.org/)
74+
.cache
75+
.parcel-cache
76+
77+
# Next.js build output
78+
.next
79+
out
80+
81+
# Nuxt.js build / generate output
82+
.nuxt
83+
dist
84+
85+
# Gatsby files
86+
.cache/
87+
# Comment in the public line in if your project uses Gatsby and not Next.js
88+
# https://nextjs.org/blog/next-9-1#public-directory-support
89+
# public
90+
91+
# vuepress build output
92+
.vuepress/dist
93+
94+
# vuepress v2.x temp and cache directory
95+
.temp
96+
.cache
97+
98+
# Sveltekit cache directory
99+
.svelte-kit/
100+
101+
# vitepress build output
102+
**/.vitepress/dist
103+
104+
# vitepress cache directory
105+
**/.vitepress/cache
106+
107+
# Docusaurus cache and generated files
108+
.docusaurus
109+
110+
# Serverless directories
111+
.serverless/
112+
113+
# FuseBox cache
114+
.fusebox/
115+
116+
# DynamoDB Local files
117+
.dynamodb/
118+
119+
# Firebase cache directory
120+
.firebase/
121+
122+
# TernJS port file
123+
.tern-port
124+
125+
# Stores VSCode versions used for testing VSCode extensions
126+
.vscode-test
127+
128+
# yarn v3
129+
.pnp.*
130+
.yarn/*
131+
!.yarn/patches
132+
!.yarn/plugins
133+
!.yarn/releases
134+
!.yarn/sdks
135+
!.yarn/versions
136+
137+
# Vite logs files
138+
vite.config.js.timestamp-*
139+
vite.config.ts.timestamp-*

README.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,33 @@
1-
# nowsecure-azure-ci-extension
1+
# nowsecure-azure-ci-extension
2+
3+
## Development
4+
5+
### Dependencies
6+
- node
7+
8+
### Making Changes
9+
10+
The core functionality is handled by the `nowsecure-ci` golang binary. The logic in `Nowsecure/index.ts` is merely a wrapper around that binary file.
11+
12+
To adjust any of the inputs / default values edit the `nowsecure/task.json`
13+
14+
To adjust any of the wrapper logic, edit `nowsecure/index.ts`
15+
16+
### Building
17+
18+
There is a convenience bash script, `publish` which can handle packaging and publishing the ADO extension.
19+
20+
To package for testing in the QA environment, run the following:
21+
22+
``` shell
23+
ENV=QA ./publish package
24+
```
25+
26+
This will create a `.vsix` file which can be uploaded to the [QA storefront](https://marketplace.visualstudio.com/publishers/qa-nowsecure)
27+
28+
## Deploying
29+
This should be handled automatically by a Github Action in the future, but the bash script in this repo can also publish directly to the [public storefront](https://marketplace.visualstudio.com/publishers/Nowsecure-com)
30+
31+
```
32+
ENV=PROD TOKEN=<some-token> ./publish publish
33+
```

nowsecure/index.ts

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import * as tl from "azure-pipelines-task-lib/task";
2+
import { ToolRunner } from "azure-pipelines-task-lib/toolrunner";
3+
import { existsSync, readFileSync } from "fs";
4+
import { join } from "path";
5+
6+
const enum Arch {
7+
X86 = "x86",
8+
X64 = "amd64",
9+
ARM = "arm"
10+
}
11+
12+
function platformToString(platform: tl.Platform) {
13+
switch (platform) {
14+
case tl.Platform.Windows:
15+
return "windows";
16+
case tl.Platform.Linux:
17+
return "linux";
18+
case tl.Platform.MacOS:
19+
return "darwin";
20+
}
21+
}
22+
23+
function chmodx(toolPath: string, platform: tl.Platform) {
24+
if (platform !== tl.Platform.Windows) {
25+
tl.execSync("chmod", ["u+x", toolPath])
26+
} else {
27+
tl.execSync("attrib", ["+x", toolPath])
28+
}
29+
}
30+
31+
function archFrom(envvar: string): Arch {
32+
switch (envvar) {
33+
case "X86":
34+
return Arch.X86
35+
case "X64":
36+
return Arch.X64
37+
case "ARM":
38+
return Arch.ARM
39+
default:
40+
const emsg = `Unknown system architecture: ${envvar}`
41+
throw new Error(emsg)
42+
}
43+
}
44+
45+
function toolName(arch: Arch, platform: tl.Platform): string {
46+
// Ex: ns_linux-amd64
47+
return `ns_${platformToString(platform)}-${arch}${platform === tl.Platform.Windows ? '.exe' : ''}`
48+
}
49+
50+
function getTool(): ToolRunner {
51+
const platform = tl.getPlatform()
52+
const arch = archFrom(tl.getVariable("Agent.OSArchitecture"))
53+
const toolPath = join(__dirname, toolName(arch, platform));
54+
55+
if (!existsSync(toolPath)) {
56+
const err =
57+
"Unsupported runner type. Integration currently supports darwin/arm64, windows/amd64, and linux/amd64"
58+
throw new Error(err)
59+
}
60+
61+
chmodx(toolPath, platform)
62+
63+
return tl.tool(toolPath)
64+
}
65+
66+
type Inputs = {
67+
// required params
68+
filepath: string;
69+
group: string;
70+
token: string;
71+
// optional params
72+
artifact_dir?: string;
73+
api_host?: string;
74+
ui_host?: string;
75+
log_level?: string;
76+
analysisType?: string;
77+
minimum_score?: string;
78+
polling_duration_minutes?: string;
79+
}
80+
81+
function getInputs(): Inputs {
82+
const inputs = {
83+
filepath: tl.getPathInputRequired("binary_file", true),
84+
group: tl.getInputRequired("group"),
85+
token: tl.getInputRequired("token"),
86+
// optional params
87+
artifact_dir: tl.getInput("artifact_dir", false),
88+
api_host: tl.getInput("api_host", false),
89+
ui_host: tl.getInput("ui_host", false),
90+
log_level: tl.getInput("log_level", false),
91+
analysisType: tl.getInput("analysis_type", false),
92+
minimum_score: tl.getInput("minimum_score", false),
93+
polling_duration_minutes: tl.getInput("polling_duration_minutes", false)
94+
}
95+
96+
if (inputs.analysisType === 'static') {
97+
inputs.polling_duration_minutes = inputs.polling_duration_minutes || '30'
98+
} else {
99+
inputs.polling_duration_minutes = inputs.polling_duration_minutes || '60'
100+
}
101+
102+
return inputs
103+
}
104+
105+
async function run() {
106+
const task = JSON.parse(readFileSync(join(__dirname, "task.json")).toString());
107+
const version = `${task.version.Major}.${task.version.Minor}.${task.version.Patch}`
108+
109+
const inputs = getInputs()
110+
111+
tl.mkdirP(inputs.artifact_dir)
112+
113+
const ns = getTool()
114+
.arg("run")
115+
.arg("file")
116+
.arg(inputs.filepath)
117+
.line(`--group-ref ${inputs.group}`)
118+
.line(`--token ${inputs.token}`)
119+
.line(`--output ${join(inputs.artifact_dir, "assessment.json")}`)
120+
.line(`--api-host ${inputs.api_host}`)
121+
.line(`--ui-host ${inputs.ui_host}`)
122+
.line(`--log-level ${inputs.log_level}`)
123+
.line(`--analysis-type ${inputs.analysisType}`)
124+
.line(`--minimum-score ${inputs.minimum_score}`)
125+
.line(`--poll-for-minutes ${inputs.polling_duration_minutes}`)
126+
.line(`--ci-environment azure-${version}`)
127+
128+
ns.on("stdout", function(data: Buffer) {
129+
console.log(data.toString());
130+
});
131+
132+
let exitCode: number
133+
exitCode = await ns.execAsync()
134+
135+
if (exitCode != 0) {
136+
const errorMessage = `NowSecure extension failed with exit code: ${exitCode}`
137+
tl.setResult(tl.TaskResult.Failed, errorMessage, true)
138+
}
139+
}
140+
141+
try {
142+
run()
143+
} catch (err) {
144+
tl.setResult(tl.TaskResult.Failed, err.message, true)
145+
}

0 commit comments

Comments
 (0)