mirror of
https://github.com/NVIDIA/TensorRT-LLM.git
synced 2026-02-05 02:31:33 +08:00
[None][infra] Add source code pulse scan to PLC nightly pipeline (#10961)
Signed-off-by: Yuanjing Xue <197832395+yuanjingx87@users.noreply.github.com>
This commit is contained in:
parent
5d7411e131
commit
f42a6cbae0
8
examples/scaffolding/contrib/mcp/weather/uv.lock
generated
Normal file
8
examples/scaffolding/contrib/mcp/weather/uv.lock
generated
Normal file
@ -0,0 +1,8 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[[package]]
|
||||
name = "mcp"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
@ -14,7 +14,6 @@ def createKubernetesPodConfig()
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
spec:
|
||||
qosClass: Guaranteed
|
||||
nodeSelector: ${selectors}
|
||||
containers:
|
||||
- name: alpine
|
||||
@ -31,10 +30,27 @@ def createKubernetesPodConfig()
|
||||
memory: 32Gi
|
||||
ephemeral-storage: 200Gi
|
||||
imagePullPolicy: Always
|
||||
- name: docker
|
||||
image: urm.nvidia.com/sw-tensorrt-docker/tensorrt-llm:202505221445_docker_dind_withbash
|
||||
tty: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 16
|
||||
memory: 72Gi
|
||||
ephemeral-storage: 200Gi
|
||||
limits:
|
||||
cpu: 16
|
||||
memory: 256Gi
|
||||
ephemeral-storage: 200Gi
|
||||
imagePullPolicy: Always
|
||||
securityContext:
|
||||
privileged: true
|
||||
capabilities:
|
||||
add:
|
||||
- SYS_ADMIN
|
||||
qosClass: Guaranteed
|
||||
""".stripIndent(),
|
||||
]
|
||||
|
||||
return podConfig
|
||||
}
|
||||
|
||||
@ -58,24 +74,34 @@ def checkoutSource ()
|
||||
{
|
||||
def LLM_REPO = getLLMRepo()
|
||||
sh "git config --global --add safe.directory ${env.WORKSPACE}"
|
||||
sh "git config --global user.email \"90828364+tensorrt-cicd@users.noreply.github.com\""
|
||||
sh "git config --global user.name \"TensorRT LLM\""
|
||||
trtllm_utils.checkoutSource(LLM_REPO, params.branchName, env.WORKSPACE, false, true)
|
||||
}
|
||||
|
||||
def generate()
|
||||
{
|
||||
sh "pwd && ls -alh"
|
||||
def getPulseToken() {
|
||||
def token
|
||||
//Configure credential 'starfleet-client-id' under Jenkins Credential Manager
|
||||
withCredentials([usernamePassword(
|
||||
credentialsId: "NSPECT_CLIENT-prod",
|
||||
usernameVariable: 'SF_CLIENT_ID',
|
||||
passwordVariable: 'SF_CLIENT_SECRET'
|
||||
)]) {
|
||||
def AuthHeader = sh(script: "set +x && echo -n $SF_CLIENT_ID:$SF_CLIENT_SECRET | base64 -w0", returnStdout: true).trim()
|
||||
token= sh(script: "curl -s --request POST --header \"Authorization: Basic ${AuthHeader}\" --header \"Content-Type: application/x-www-form-urlencoded\" \"https://4ubglassowmtsi7ogqwarmut7msn1q5ynts62fwnr1i.ssa.nvidia.com/token?grant_type=client_credentials&scope=verify:nspectid%20sourcecode:blackduck%20update:report\" | jq \".access_token\" | tr -d '\"'", returnStdout: true).trim()
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
def generateLockFiles(llmRepo, branchName)
|
||||
{
|
||||
container("alpine") {
|
||||
sh "apt update"
|
||||
sh "apt install -y python3-dev git curl git-lfs"
|
||||
def LLM_REPO = getLLMRepo()
|
||||
checkoutSource()
|
||||
sh "python3 --version"
|
||||
sh "curl -sSL https://install.python-poetry.org | python3 -"
|
||||
sh "cd ${env.WORKSPACE}"
|
||||
sh "/root/.local/bin/poetry -h"
|
||||
sh "git config --global --add safe.directory ${env.WORKSPACE}"
|
||||
sh "git config --global user.email \"90828364+tensorrt-cicd@users.noreply.github.com\""
|
||||
sh "git config --global user.name \"TensorRT LLM\""
|
||||
sh "export PATH=\"/root/.local/bin:\$PATH\" && python3 scripts/generate_lock_file.py"
|
||||
def count = sh(script: "git status --porcelain security_scanning/ | wc -l", returnStdout: true).trim()
|
||||
echo "Changed/untracked file count: ${count}"
|
||||
@ -96,15 +122,15 @@ def generate()
|
||||
]) {
|
||||
def authedUrl
|
||||
if (params.repoUrlKey == "tensorrt_llm_internal") {
|
||||
authedUrl = LLM_REPO.replaceFirst('https://', "https://svc_tensorrt:${GITLAB_API_TOKEN}@")
|
||||
authedUrl = llmRepo.replaceFirst('https://', "https://svc_tensorrt:${GITLAB_API_TOKEN}@")
|
||||
} else {
|
||||
authedUrl = LLM_REPO.replaceFirst('https://', "https://svc_tensorrt:${GITHUB_API_TOKEN}@")
|
||||
authedUrl = llmRepo.replaceFirst('https://', "https://svc_tensorrt:${GITHUB_API_TOKEN}@")
|
||||
}
|
||||
sh "git remote set-url origin ${authedUrl}"
|
||||
sh "git fetch origin ${params.branchName}"
|
||||
sh "git fetch origin ${branchName}"
|
||||
sh "git status"
|
||||
sh "git rebase origin/${params.branchName}"
|
||||
sh "git push origin HEAD:${params.branchName}"
|
||||
sh "git rebase origin/${branchName}"
|
||||
sh "git push origin HEAD:${branchName}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,6 +151,51 @@ def sonar_scan()
|
||||
}
|
||||
}
|
||||
|
||||
def pulseScan(llmRepo, branchName) {
|
||||
container("docker") {
|
||||
sh "apk add jq curl"
|
||||
def token = getPulseToken()
|
||||
withCredentials([
|
||||
usernamePassword(
|
||||
credentialsId: "svc_tensorrt_gitlab_read_api_token",
|
||||
usernameVariable: 'USERNAME',
|
||||
passwordVariable: 'PASSWORD'
|
||||
),
|
||||
string(credentialsId: 'default-git-url', variable: 'DEFAULT_GIT_URL')
|
||||
]) {
|
||||
trtllm_utils.llmExecStepWithRetry(this, script: "docker login ${DEFAULT_GIT_URL}:5005 -u ${USERNAME} -p ${PASSWORD}")
|
||||
docker.withRegistry("https://${DEFAULT_GIT_URL}:5005") {
|
||||
docker.image("pstooling/pulse-group/pulse-open-source-scanner/pulse-oss-cli:stable")
|
||||
.inside("--user 0 --privileged -v /var/run/docker.sock:/var/run/docker.sock") {
|
||||
withEnv([
|
||||
"PULSE_NSPECT_ID=NSPECT-95LK-6FZF",
|
||||
"PULSE_BEARER_TOKEN=${token}",
|
||||
"PULSE_REPO_URL=${llmRepo}",
|
||||
"PULSE_SCAN_PROJECT=TRT-LLM",
|
||||
"PULSE_SCAN_PROJECT_VERSION=${branchName}",
|
||||
"PULSE_SCAN_VULNERABILITY_REPORT=nspect_scan_report.json"
|
||||
]) {
|
||||
sh 'pulse scan --no-fail .'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sh "ls"
|
||||
sh "cat nspect_scan_report.json"
|
||||
withCredentials([string(credentialsId: 'trtllm_plc_slack_webhook', variable: 'PLC_SLACK_WEBHOOK')]) {
|
||||
def jobPath = env.JOB_NAME.replaceAll("/", "%2F")
|
||||
def pipelineUrl = "${env.JENKINS_URL}blue/organizations/jenkins/${jobPath}/detail/${jobPath}/${env.BUILD_NUMBER}/pipeline"
|
||||
sh """
|
||||
export TRTLLM_PLC_WEBHOOK=${PLC_SLACK_WEBHOOK}
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install requests
|
||||
python ./jenkins/scripts/submit_vulnerability_report.py --build-url ${pipelineUrl}
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pipeline {
|
||||
agent {
|
||||
kubernetes createKubernetesPodConfig()
|
||||
@ -139,6 +210,10 @@ pipeline {
|
||||
timestamps()
|
||||
timeout(time: 60, unit: 'MINUTES')
|
||||
}
|
||||
environment {
|
||||
LLM_REPO = getLLMRepo()
|
||||
BRANCH_NAME = "${params.branchName}"
|
||||
}
|
||||
|
||||
triggers {
|
||||
parameterizedCron('''
|
||||
@ -150,13 +225,30 @@ pipeline {
|
||||
stages {
|
||||
stage('TRT-LLM PLC Jobs') {
|
||||
parallel {
|
||||
stage("Generating Poetry Locks"){
|
||||
stage("Source Code OSS Scanning"){
|
||||
agent {
|
||||
kubernetes createKubernetesPodConfig()
|
||||
}
|
||||
steps
|
||||
{
|
||||
generate()
|
||||
stages {
|
||||
stage("Prepare Environment"){
|
||||
steps
|
||||
{
|
||||
checkoutSource()
|
||||
sh "cd ${env.WORKSPACE}"
|
||||
}
|
||||
}
|
||||
stage("Generate Lock Files"){
|
||||
steps
|
||||
{
|
||||
generateLockFiles(env.LLM_REPO, env.BRANCH_NAME)
|
||||
}
|
||||
}
|
||||
stage("Run Pulse Scanning"){
|
||||
steps
|
||||
{
|
||||
pulseScan(env.LLM_REPO, env.BRANCH_NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage("SonarQube Code Analysis"){
|
||||
|
||||
60
jenkins/scripts/submit_vulnerability_report.py
Normal file
60
jenkins/scripts/submit_vulnerability_report.py
Normal file
@ -0,0 +1,60 @@
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
|
||||
# slack workflow setting can be edited at https://slack.com/shortcuts/Ft0AAER075L3/a314cf6f4a81543cc37b75702c5d10f1
|
||||
SLACK_WEBHOOK_URL = os.environ.get("TRTLLM_PLC_WEBHOOK")
|
||||
# this json file will be generated from pulse in pipeline scanning
|
||||
INPUT_FILE = "./nspect_scan_report.json"
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--build-url", required=True, help="Jenkins build URL")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Throw error if not set
|
||||
if not SLACK_WEBHOOK_URL:
|
||||
raise EnvironmentError("Error: Environment variable 'TRTLLM_PLC_WEBHOOK' is not set!")
|
||||
|
||||
# Read file
|
||||
raw_input = Path(INPUT_FILE).read_text()
|
||||
vulnerabilities = json.loads(raw_input)
|
||||
|
||||
|
||||
def safe(value, default="N/A"):
|
||||
return value if value else default
|
||||
|
||||
|
||||
# Build attachment text
|
||||
message_lines = ["* TensorRT LLM Source Code Vulnerability Scan Report*\n"]
|
||||
|
||||
severity_rank = {"Critical": 4, "High": 3, "Medium": 2, "Low": 1}
|
||||
|
||||
for v in vulnerabilities:
|
||||
sev = v.get("Severity", "Low")
|
||||
if severity_rank.get(sev, 0) <= 2:
|
||||
continue
|
||||
shortTermVersion = safe(v.get("Upgrade-Guidance", {}).get("Short-Term"))
|
||||
longTermVersion = safe(v.get("Upgrade-Guidance", {}).get("Long-Term"))
|
||||
lines = [
|
||||
f"🔴 *{safe(v.get('Severity'))}* — *{safe(v.get('Package Name'))}* `{safe(v.get('Package Version'))}`",
|
||||
f"• *CVE:* {safe(v.get('Related Vuln'))} | *BDSA:* {safe(v.get('CVE ID'))}",
|
||||
f"• *Score:* {safe(v.get('Score'))}",
|
||||
f"• *Status:* {safe(v.get('Status'))}",
|
||||
f"• *Published:* {safe(v.get('Vulnerability Published Date'))}",
|
||||
f"• *Upgrade:* `{shortTermVersion}` → `{longTermVersion}`",
|
||||
"─" * 40, # separator line
|
||||
]
|
||||
message_lines.extend(lines)
|
||||
|
||||
message_text = "\n".join(message_lines)
|
||||
|
||||
payload = {"report": message_text, "pipelineUrl": args.build_url}
|
||||
|
||||
print(payload)
|
||||
# Send to Slack
|
||||
resp = requests.post(SLACK_WEBHOOK_URL, json=payload, timeout=60)
|
||||
resp.raise_for_status()
|
||||
Loading…
Reference in New Issue
Block a user