@vibecontrols/vibe-plugin-security-sbom-build 2026.528.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +8 -0
- package/README.md +24 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/provider.d.ts +17 -0
- package/dist/tools-manifest.d.ts +12 -0
- package/package.json +83 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Proprietary License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Burdenoff Consultancy Services Pvt. Ltd. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are
|
|
6
|
+
proprietary to Burdenoff Consultancy Services Pvt. Ltd. ("Burdenoff").
|
|
7
|
+
|
|
8
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @vibecontrols/vibe-plugin-security-sbom-build
|
|
2
|
+
|
|
3
|
+
Generates a CycloneDX SBOM via Syft and scans it for known vulnerabilities via Grype. Targets the `build` lifecycle stage in [VibeControls](https://vibecontrols.com).
|
|
4
|
+
|
|
5
|
+
Registers as a `security.sbom` provider (name `syft-grype`) with the [`@vibecontrols/vibe-plugin-security`](https://www.npmjs.com/package/@vibecontrols/vibe-plugin-security) meta plugin.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
vibe plugin install @vibecontrols/vibe-plugin-security-sbom-build
|
|
11
|
+
vibe security providers set-default --stage build --provider syft-grype
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Both Syft (Anchore) and Grype (Anchore) binaries are downloaded automatically on first use with sha256 verification.
|
|
15
|
+
|
|
16
|
+
## Outputs
|
|
17
|
+
|
|
18
|
+
- `sbom.cdx.json` — CycloneDX 1.5 SBOM (evidence type `sbom-cyclonedx`)
|
|
19
|
+
- `grype.json` — Grype vulnerability report (evidence type `grype-json`)
|
|
20
|
+
- `NormalizedFinding[]` — one row per `matches[]` entry with CVE, package, fix version, severity
|
|
21
|
+
|
|
22
|
+
## License
|
|
23
|
+
|
|
24
|
+
Proprietary — Burdenoff Consultancy Services Pvt. Ltd.
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{ProviderRegistry,TelemetryEmitter,createLifecycleHooks}from"@vibecontrols/plugin-sdk";import{spawn}from"child_process";import{createHash}from"crypto";import{promises as fs}from"fs";import*as path from"path";import{normalizeGrype}from"@vibecontrols/vibe-plugin-security/normalizer";import{resolveToolPath}from"@vibecontrols/vibe-plugin-security/tool-installer";var SYFT_VERSION="1.18.1",GRYPE_VERSION="0.85.0",TOOLS_MANIFEST={syft:{version:"1.18.1",binaryName:"syft",versionMatcher:"1.18.1".replace(/\./g,"\\."),downloads:{"linux-x64":{url:"https://github.com/anchore/syft/releases/download/v1.18.1/syft_1.18.1_linux_amd64.tar.gz",sha256:"066c251652221e4d44fcc4d115ce3df33a91769da38c830a8533199db2f65aab",binaryWithinArchive:"syft",archive:"tar.gz"},"linux-arm64":{url:"https://github.com/anchore/syft/releases/download/v1.18.1/syft_1.18.1_linux_arm64.tar.gz",sha256:"cd228306e5cb0654baecb454f76611606b84899d27fa9ceb7da4df46b94fe84e",binaryWithinArchive:"syft",archive:"tar.gz"},"darwin-x64":{url:"https://github.com/anchore/syft/releases/download/v1.18.1/syft_1.18.1_darwin_amd64.tar.gz",sha256:"223f5a97653e0bb0a96580a04328d41d515ee742bfbdd917f0583dc43e66f423",binaryWithinArchive:"syft",archive:"tar.gz"},"darwin-arm64":{url:"https://github.com/anchore/syft/releases/download/v1.18.1/syft_1.18.1_darwin_arm64.tar.gz",sha256:"bc5ad238a7cc60f19459b6f358079847bff5f8e520c8239706730f3fc5c5edd5",binaryWithinArchive:"syft",archive:"tar.gz"}}},grype:{version:"0.85.0",binaryName:"grype",versionMatcher:"0.85.0".replace(/\./g,"\\."),downloads:{"linux-x64":{url:"https://github.com/anchore/grype/releases/download/v0.85.0/grype_0.85.0_linux_amd64.tar.gz",sha256:"89f8ccbaa7a47abab90e9e894a925a92ef47a4d2bf0981001e654527378d6ed4",binaryWithinArchive:"grype",archive:"tar.gz"},"linux-arm64":{url:"https://github.com/anchore/grype/releases/download/v0.85.0/grype_0.85.0_linux_arm64.tar.gz",sha256:"aa96abd5bd6912f50ee1763a445a49dc37fafdc2a8354876f7e4802341701f7c",binaryWithinArchive:"grype",archive:"tar.gz"},"darwin-x64":{url:"https://github.com/anchore/grype/releases/download/v0.85.0/grype_0.85.0_darwin_amd64.tar.gz",sha256:"c66e5939b1cf11b63855d5d16b291740ae0bf46b3a0f87689d164de652a57d8c",binaryWithinArchive:"grype",archive:"tar.gz"},"darwin-arm64":{url:"https://github.com/anchore/grype/releases/download/v0.85.0/grype_0.85.0_darwin_arm64.tar.gz",sha256:"88b7270120fb761b56742ee1d946849fd722d790c8dc31b28ce7ad1d71f44d6b",binaryWithinArchive:"grype",archive:"tar.gz"}}}};class SbomBuildProvider{name="syft-grype";stage="build";toolVersion=`syft@${SYFT_VERSION}+grype@${GRYPE_VERSION}`;host;syftPath;grypePath;active=new Map;async init(host){this.host=host}async ensureToolInstalled(){let ctx={dataDir:this.host?.getDataDir?.()??path.join(process.env.HOME??".",".boff/vibecontrols"),log:{info:(m)=>this.host?.logger?.info?.("sbom-build-provider",m),warn:(m)=>this.host?.logger?.warn?.("sbom-build-provider",m),error:(m)=>this.host?.logger?.error?.("sbom-build-provider",m)}};this.syftPath=await resolveToolPath(ctx,"syft",TOOLS_MANIFEST.syft),this.grypePath=await resolveToolPath(ctx,"grype",TOOLS_MANIFEST.grype)}async run(input){if(!this.syftPath||!this.grypePath)await this.ensureToolInstalled();if(!this.syftPath||!this.grypePath)throw Error("sbom-build-provider: tool paths unavailable");let startedAt=Date.now(),cfg=input.config??{},sbomFormat=cfg.syftFormat??"cyclonedx-json",sbomPath=path.join(input.workdir,sbomFormat==="spdx-json"?"sbom.spdx.json":"sbom.cdx.json"),grypePath=path.join(input.workdir,"grype.json");input.onProgress?.({pct:5,message:"Generating SBOM via Syft"});let syftArgs=["scan",`dir:${input.repoLocalPath}`,"-o",`${sbomFormat}=${sbomPath}`];if(cfg.extraSyftArgs)syftArgs.push(...cfg.extraSyftArgs);let syftResult=await this.spawnAndWait(this.syftPath,input.runId,syftArgs);if(syftResult.code!==0)return errored(input.runId,startedAt,`syft exited ${syftResult.code}: ${syftResult.stderr.slice(0,500)}`);input.onProgress?.({pct:50,message:"Scanning SBOM via Grype"});let grypeArgs=["sbom:"+sbomPath,"-o","json","--file",grypePath];if(cfg.extraGrypeArgs)grypeArgs.push(...cfg.extraGrypeArgs);let grypeResult=await this.spawnAndWait(this.grypePath,input.runId,grypeArgs);if(grypeResult.code!==0)return errored(input.runId,startedAt,`grype exited ${grypeResult.code}: ${grypeResult.stderr.slice(0,500)}`);input.onProgress?.({pct:85,message:"Normalizing findings"});let grypeRaw=await fs.readFile(grypePath,"utf-8"),findings=normalizeGrype(grypeRaw,this.name),evidence=[];for(let[type,p]of[[sbomFormat==="spdx-json"?"sbom-spdx":"sbom-cyclonedx",sbomPath],["grype-json",grypePath]])try{let buf=await fs.readFile(p);evidence.push({type,localPath:p,sha256:createHash("sha256").update(buf).digest("hex"),sizeBytes:buf.byteLength})}catch{}return input.onProgress?.({pct:100,message:"Scan complete"}),{runId:input.runId,status:"succeeded",findings,evidence,durationMs:Date.now()-startedAt,summary:summarize(findings)}}async cancel(runId){let child=this.active.get(runId);if(!child)return;child.kill("SIGTERM"),setTimeout(()=>{try{child.kill("SIGKILL")}catch{}},5000),this.active.delete(runId)}metadata(){return{stage:this.stage,supportedProfiles:["backend","frontend","cli","sdk","mcp","container","iac"],toolVersion:this.toolVersion,description:"Syft generates SBOM, Grype scans for vulnerabilities (build stage)."}}spawnAndWait(bin,runId,args){return new Promise((resolve)=>{let child=spawn(bin,args,{stdio:["ignore","pipe","pipe"]});this.active.set(runId,child);let stdout="",stderr="";child.stdout?.on("data",(b)=>stdout+=b.toString()),child.stderr?.on("data",(b)=>stderr+=b.toString()),child.on("close",(code)=>{this.active.delete(runId),resolve({code,stdout,stderr})}),child.on("error",(err)=>{this.active.delete(runId),resolve({code:-1,stdout,stderr:err.message})})})}}function summarize(findings){let s={critical:0,high:0,medium:0,low:0,info:0};for(let f of findings)s[f.severity]++;return s}function errored(runId,startedAt,reason){return{runId,status:"errored",findings:[],evidence:[],durationMs:Date.now()-startedAt,summary:{critical:0,high:0,medium:0,low:0,info:0},errorReason:reason}}var PLUGIN_NAME="security-sbom-build",PLUGIN_VERSION="2026.527.1",createPlugin=(_ctx)=>{let provider=new SbomBuildProvider,telemetry=new TelemetryEmitter(PLUGIN_NAME,PLUGIN_VERSION),lifecycle=createLifecycleHooks({name:PLUGIN_NAME,telemetryEventName:"security.sbom-build.ready",onInit:async(host)=>{await provider.init(host),new ProviderRegistry(host).registerProvider("security.sbom","syft-grype",provider),telemetry.emit("security.sbom-build.registered",{provider:"syft-grype",toolVersion:provider.toolVersion})}});return{name:PLUGIN_NAME,version:PLUGIN_VERSION,description:"Syft + Grype SBOM/vuln scanner for the build stage.",tags:["backend","provider","integration"],capabilities:{storage:"rw",subprocess:!0,audit:!0,telemetry:!0},onServerStart:lifecycle.onServerStart,onServerStop:lifecycle.onServerStop}},src_default=createPlugin;export{src_default as default,createPlugin,SbomBuildProvider};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HostServices } from "@vibecontrols/plugin-sdk/contract";
|
|
2
|
+
import type { SecurityProvider, SecurityProviderMetadata, SecurityScanInput, SecurityScanResult, SecurityStage } from "@vibecontrols/vibe-plugin-security/types";
|
|
3
|
+
export declare class SbomBuildProvider implements SecurityProvider {
|
|
4
|
+
readonly name = "syft-grype";
|
|
5
|
+
readonly stage: SecurityStage;
|
|
6
|
+
readonly toolVersion = "syft@1.18.1+grype@0.85.0";
|
|
7
|
+
private host?;
|
|
8
|
+
private syftPath?;
|
|
9
|
+
private grypePath?;
|
|
10
|
+
private active;
|
|
11
|
+
init(host: HostServices): Promise<void>;
|
|
12
|
+
ensureToolInstalled(): Promise<void>;
|
|
13
|
+
run(input: SecurityScanInput): Promise<SecurityScanResult>;
|
|
14
|
+
cancel(runId: string): Promise<void>;
|
|
15
|
+
metadata(): SecurityProviderMetadata;
|
|
16
|
+
private spawnAndWait;
|
|
17
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Syft + Grype manifest. Versions + sha256 pinned per CalVer release.
|
|
3
|
+
* Checksums sourced from the upstream Anchore release checksums file.
|
|
4
|
+
*
|
|
5
|
+
* To refresh:
|
|
6
|
+
* curl -sL https://github.com/anchore/syft/releases/download/v<VER>/syft_<VER>_checksums.txt
|
|
7
|
+
* curl -sL https://github.com/anchore/grype/releases/download/v<VER>/grype_<VER>_checksums.txt
|
|
8
|
+
*/
|
|
9
|
+
import type { ToolManifest } from "@vibecontrols/vibe-plugin-security/tool-installer";
|
|
10
|
+
export declare const SYFT_VERSION = "1.18.1";
|
|
11
|
+
export declare const GRYPE_VERSION = "0.85.0";
|
|
12
|
+
export declare const TOOLS_MANIFEST: ToolManifest;
|
package/package.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vibecontrols/vibe-plugin-security-sbom-build",
|
|
3
|
+
"version": "2026.528.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"description": "Syft + Grype provider for the build lifecycle stage. Generates a CycloneDX SBOM and scans it for known vulnerabilities. Registers as a security.sbom provider with @vibecontrols/vibe-plugin-security.",
|
|
8
|
+
"engines": {
|
|
9
|
+
"bun": ">=1.3.14"
|
|
10
|
+
},
|
|
11
|
+
"author": {
|
|
12
|
+
"name": "Vignesh T.V",
|
|
13
|
+
"email": "vignesh@burdenoff.com",
|
|
14
|
+
"url": "https://github.com/tvvignesh"
|
|
15
|
+
},
|
|
16
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "bun build ./src/index.ts --outdir ./dist --target bun --minify-syntax --minify-whitespace --external elysia --external @vibecontrols/vibe-plugin-security --external @vibecontrols/plugin-sdk && tsc --emitDeclarationOnly --declaration --outDir ./dist",
|
|
19
|
+
"dev": "tsc --watch",
|
|
20
|
+
"lint": "eslint ./src ./tests",
|
|
21
|
+
"format": "bunx prettier . --write",
|
|
22
|
+
"format:check": "bunx prettier . --check",
|
|
23
|
+
"type:check": "tsc --noEmit",
|
|
24
|
+
"test": "bun test ./tests",
|
|
25
|
+
"clean": "rimraf dist",
|
|
26
|
+
"prebuild": "bun run clean",
|
|
27
|
+
"prepublishOnly": "bun run build",
|
|
28
|
+
"sanity": "bun run format:check && bun run lint && bun run type:check && bun run test && bun run build"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@vibecontrols/plugin-sdk": "2026.527.1",
|
|
32
|
+
"@vibecontrols/vibe-plugin-security": "2026.528.1"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@eslint/js": "^10.0.1",
|
|
36
|
+
"@types/node": "^22.0.0",
|
|
37
|
+
"bun-types": "^1.3.9",
|
|
38
|
+
"eslint": "^9.30.1",
|
|
39
|
+
"globals": "^17.3.0",
|
|
40
|
+
"prettier": "^3.6.2",
|
|
41
|
+
"rimraf": "^6.0.1",
|
|
42
|
+
"typescript": "^5.9.3",
|
|
43
|
+
"typescript-eslint": "^8.56.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@vibecontrols/agent": ">=2026.428.0"
|
|
47
|
+
},
|
|
48
|
+
"peerDependenciesMeta": {
|
|
49
|
+
"@vibecontrols/agent": {
|
|
50
|
+
"optional": true
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"keywords": [
|
|
54
|
+
"vibecontrols",
|
|
55
|
+
"vibe",
|
|
56
|
+
"vibe-plugin",
|
|
57
|
+
"security",
|
|
58
|
+
"sbom",
|
|
59
|
+
"syft",
|
|
60
|
+
"grype",
|
|
61
|
+
"cyclonedx",
|
|
62
|
+
"supply-chain",
|
|
63
|
+
"bun"
|
|
64
|
+
],
|
|
65
|
+
"repository": {
|
|
66
|
+
"type": "git",
|
|
67
|
+
"url": "git+https://github.com/algoshred/vibe-plugin-security-sbom-build.git"
|
|
68
|
+
},
|
|
69
|
+
"bugs": {
|
|
70
|
+
"url": "https://github.com/algoshred/vibe-plugin-security-sbom-build/issues"
|
|
71
|
+
},
|
|
72
|
+
"homepage": "https://vibecontrols.com",
|
|
73
|
+
"publishConfig": {
|
|
74
|
+
"access": "public",
|
|
75
|
+
"registry": "https://registry.npmjs.org/"
|
|
76
|
+
},
|
|
77
|
+
"files": [
|
|
78
|
+
"dist/**/*",
|
|
79
|
+
"!dist/**/*.map",
|
|
80
|
+
"README.md",
|
|
81
|
+
"LICENSE"
|
|
82
|
+
]
|
|
83
|
+
}
|