Hver linje kode, der når produktion, blev committet af en person, der troede, den var korrekt. Statisk kodeanalyse er det automatiserede system, der kontrollerer, om denne tro var korrekt, ikke ved at køre koden, men ved at læse dens struktur, spore dens datastrømme og sammenligne den med kendte mønstre af sårbarheder, fejl og kvalitetsbrud. Spørgsmålet er ikke, om den skal køres, men hvor i pipelinen den skal køres, hvilket værktøj der skal køres, hvilke tærskler der skal håndhæves, og hvordan man holder feedbacken hurtig nok til, at udviklere rent faktisk handler på den i stedet for at ignorere den.
Forskellen mellem statisk analyse som en afkrydsningsfeltaktivitet og statisk analyse som en ægte kvalitetsgate er konfigurationen. En scanner, der kører og producerer en rapport, som ingen læser, er et teater. En kvalitetsgate, der fejler en build, når nye kritiske sårbarheder introduceres, blokerer en merge, når dækningen falder under tærsklen, og viser præcis fil- og linjefeedback i pull request-gennemgangsgrænsefladen, er et system, der ændrer adfærd i det øjeblik, beslutninger træffes.
Hvor i pipelinen skal statisk analyse køres
Statisk analyse bør køres på flere punkter, der hver især tjener et forskelligt formål. At køre den kun på ét punkt skaber blinde vinkler; at køre den overalt skaber ligeledes langsomme pipelines, som udviklere ruter udenom.
| Rørledningsfase | Hvad skal man løbe | Latensbudget | Formål |
|---|---|---|---|
| Forhåndsgodkendelse (lokal) | Kun hurtig linters (ESLint, Clippy, rustfmt) | Under 5 sekunder | Stop åbenlyse problemer, før de rammer repositoriet |
| Pull request / merge request | Fuld linting + SAST + trinvis SonarQube-scanning | Under 3 minutter | Blokfletninger ved nye kritiske problemer |
| Opbygning af hovedgren | Fuld analyse inklusive dækning, duplikering, teknisk gæld | Under 10 minutter | Spor kvalitetstendenser, opdater dashboards |
| Planlagt hver nat | Dybe scanninger, afhængighedsrevision, compliance-tjek | Intet budget | Opdag problemer med langsom byggeproces og risiko i forsyningskæden |
Den mest værdifulde fase er pull request'enAnalyse, der kører på push to main, ankommer efter beslutningen om merge er truffet. Analyse, der kører på en pull-anmodning og sender indlejrede kommentarer med præcis fil- og linjekontekst, ankommer, når udvikleren stadig er i koden, og omkostningerne ved rettelse er lavest.
At køre tung analyse før hver gemning ødelægger udvikleroplevelsen. Hurtige linters, der fuldføres på under 5 sekunder, hører hjemme der. Alt andet hører hjemme i CI.
GitHub-handlinger: Fuldfør fungerende konfiguration
GitHub Actions er den mest anvendte CI-platform. Følgende arbejdsgang kører en lagdelt kvalitetspipeline: formateringskontrol, linting, build, SAST-sikkerhedsscanning og SonarCloud-kvalitetsgate.
yaml
# .github/workflows/quality.yml
name: Code Quality
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
# ── Layer 1: Fast checks (under 60 seconds) ─────────────────────────────
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- name: Lint (fail on warnings)
run: npx eslint src/ --max-warnings 0
- name: Format check
run: npx prettier --check src/
- name: TypeScript type check
run: npx tsc --noEmit
# ── Layer 2: Security SAST (Semgrep) ────────────────────────────────────
sast:
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- name: Semgrep SAST scan
uses: semgrep/semgrep-action@v1
with:
config: p/javascript p/nodejs p/owasp-top-ten
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
# ── Layer 3: SonarCloud quality gate ────────────────────────────────────
sonar:
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history required for blame data
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- name: Run tests with coverage
run: npm test -- --coverage --coverageReporters=lcov
- name: SonarCloud scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
egenskaber
# sonar-project.properties
sonar.projectKey=my-org_my-project
sonar.organization=my-org
sonar.sources=src
sonar.tests=tests
sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.coverage.exclusions=**/*.test.js,**/*.spec.js
Vigtige konfigurationsbeslutninger i denne arbejdsgang:
--max-warnings 0På ESLint: Enhver advarsel er en buildfejl. Hold, der tillader advarsler, akkumulerer dem, indtil ingen læser dem.fetch-depth: 0Ved betaling: SonarCloud har brug for fuld git-historik for at kunne tildele skylden til introducerede problemer og beregne metrikker for ny kode korrekt.- Semgrep kører efter lint parallelt med Sonar: sikkerheds- og kvalitetsscanning er uafhængige hensyn; parallel kørsel af dem reducerer den samlede pipeline-tid.
- Test køres med
lcovdækningsoutput: SonarCloud læser dette for at vise dækning pr. fil og håndhæve dækningstærskler i kvalitetsportalen.
GitLab CI/CD: Kvalitetspipeline med kvalitetsporte
yaml
# .gitlab-ci.yml
stages:
- lint
- test
- analyze
- security
variables:
SONAR_HOST_URL: "https://sonarcloud.io"
lint:
stage: lint
image: node:20
cache:
paths: [node_modules/]
script:
- npm ci
- npx eslint src/ --max-warnings 0
- npx prettier --check src/
- npx tsc --noEmit
rules:
- if: $CI_MERGE_REQUEST_IID
- if: $CI_COMMIT_BRANCH == "main"
test:
stage: test
image: node:20
script:
- npm ci
- npm test -- --coverage --coverageReporters=lcov cobertura
coverage: '/Lines\s*:\s*(\d+\.?\d*)%/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
sonarcloud:
stage: analyze
image:
name: sonarsource/sonar-scanner-cli:latest
entrypoint: [""]
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
GIT_DEPTH: "0"
cache:
key: "${CI_JOB_NAME}"
paths: [.sonar/cache]
script:
- sonar-scanner
rules:
- if: $CI_MERGE_REQUEST_IID
- if: $CI_COMMIT_BRANCH == "main"
semgrep:
stage: security
image: returntocorp/semgrep:latest
script:
- semgrep scan --config=p/owasp-top-ten --config=p/javascript
--sarif --output=semgrep.sarif src/
artifacts:
reports:
sast: semgrep.sarif
rules:
- if: $CI_MERGE_REQUEST_IID
- if: $CI_COMMIT_BRANCH == "main"
artifacts: reports: sast: block integrerer SARIF-output fra Semgrep direkte i GitLabs sikkerhedsdashboard, hvor resultaterne vises i sikkerhedsrapporten for mergeanmodningen i stedet for som rå CI-logoutput.
Jenkins: Deklarativ pipeline med SonarQube
Groovy
// Jenkinsfile
pipeline {
agent any
tools {
nodejs "NodeJS-20"
}
environment {
SONAR_TOKEN = credentials('sonar-token')
}
stages {
stage('Lint') {
steps {
sh 'npm ci'
sh 'npx eslint src/ --max-warnings 0'
sh 'npx tsc --noEmit'
}
}
stage('Test') {
steps {
sh 'npm test -- --coverage --coverageReporters=lcov'
}
post {
always {
publishHTML([
allowMissing: false,
reportDir: 'coverage/lcov-report',
reportFiles: 'index.html',
reportName: 'Coverage Report'
])
}
}
}
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('SonarQube') {
sh '''
npx sonar-scanner \
-Dsonar.projectKey=my-project \
-Dsonar.sources=src \
-Dsonar.javascript.lcov.reportPaths=coverage/lcov.info
'''
}
}
}
stage('Quality Gate') {
steps {
timeout(time: 5, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}
}
post {
failure {
emailext(
subject: "Quality Gate FAILED: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Build failed quality gate. Review: ${env.BUILD_URL}",
to: "${env.CHANGE_AUTHOR_EMAIL}"
)
}
}
}
waitForQualityGate abortPipeline: true er den kritiske linje. Den afspørger SonarQube, indtil analysen er færdig, og fejler build'et, hvis kvalitetsgrænsen ikke er opfyldt. Uden dette fuldføres pipelinen, mens analysen stadig kører, og kvalitetsgrænsens resultat håndhæves aldrig.
Konfiguration af kvalitetsporte, som teams rent faktisk respekterer
En kvalitetsgate, der fejler ved hver commit, fordi tærsklerne er sat for aggressivt, deaktiveres. En gate, der aldrig fejler, fordi tærsklerne er for permissive, giver ingen værdi. Målet er en gate, der er kalibreret til projektets faktiske risikoprofil.
Anbefalet startkonfiguration for en ny SonarQube kvalitetsport:
| metric | Betingelse | Threshold |
|---|---|---|
| Nye fejl | Større end | 0 |
| Nye sårbarheder | Større end | 0 |
| Nye sikkerhedshotspots gennemgået | Mindre end | 100% |
| Ny kodedækning | Mindre end | 80% |
| Nye duplikerede linjer | Større end | 3% |
| Ny kode lugter | Større end | 10 |
Anvend disse tærskler på kun ny kode (den "nye kode"-periode i SonarQube). Anvend dem ikke på den fulde kodebase på et ældre projekt, da fejl i hvert build på grund af teknisk gæld akkumuleret over fem år vil medføre, at teams deaktiverer porten helt. Tilgangen med ny kode giver dig mulighed for at stoppe blødningen, mens den eksisterende gæld håndteres separat.
Skraldetærskler over tid. Start med konservative tærskler, og stram dem derefter hvert kvartal, efterhånden som teamet afvikler sin efterslæb. En gate, der består i dag med 75% dækning, kan opdateres til 80%, når baseline er komfortabelt over det. Trinvis stramning er mere bæredygtig end at springe til perfektion.
Håndtering af statisk analyseydelse i store kodebaser
Den mest almindelige årsag til, at teams deaktiverer eller omgår statisk analyse i CI, er, at det gør pipelines for langsomme. En 15-minutters kvalitetsscanning ved hvert push til en feature branch ødelægger udviklerflowet. Der er flere strategier, der holder analysen hurtig:
Trinvis analyse (kun ny kode). SonarQube og de fleste statiske analyseværktøjer til virksomheder understøtter kun analyse af de ændrede filer i en pull-anmodning i stedet for hele kodebasen. sonar.pullrequest.base, sonar.pullrequest.branchog sonar.pullrequest.key parametre for at aktivere PR-specifik inkrementel scanning. Fuld analyse kører stadig ved merge til main; PR-scanning tager under 2 minutter på de fleste kodebaser.
Caching. Den dyreste del af mange statiske analysekørsler er at downloade værktøjet og dets regeldefinitioner. Cache scannerbinærfilen, regeldatabasen og eventuelle løste afhængigheder mellem kørsler:
yaml
# GitHub Actions: cache SonarCloud scanner
- name: Cache SonarCloud packages
uses: actions/cache@v4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
Parallelisme. Linting, sikkerhedsscanning og analyse af kvalitetsgate er uafhængige aspekter. Kør dem parallelle job i stedet for sekventielt. Den samlede pipelinetid bestemmes af det langsomste job, ikke summen af alle job.
Selektiv værktøjsaktivering. Ikke alle værktøjer behøver at køre på alle brancher. Fuld sikkerhedsscanning og compliance-tjek kan køres på pull requests og main, mens pre-merge branches kun kører hurtige linters. Brug branch-filtre i CI-konfigurationen til at anvende forskellige analyseprofiler.
Statisk analyse i sikkerhedsorienterede pipelines: SAST og afhængighedsscanning
Sikkerhedsfokuserede pipelines tilføjer to lag ud over standard kvalitetsanalyse: SAST (Static Application Security Testing) for sårbarheder i applikationskode og afhængighedsscanning for kendte CVE'er i tredjepartsbiblioteker.
SAST-værktøjer (Semgrep, CodeQL, Snyk Code, Checkmarx) analyserer, hvordan upålidelige data flyder gennem applikationskode og når følsomme operationer. De finder SQL-injektion, XSS, kommandoinjektion, usikker deserialisering og hardcodede legitimationsoplysninger, som standard-lintere ikke kan registrere.
yaml
# GitHub Actions: CodeQL analysis for deep vulnerability detection
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: javascript-typescript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:javascript-typescript"
Afhængighedsscanning kontrol package.json, pom.xml, requirements.txtog tilsvarende manifestfiler mod sårbarhedsdatabaser:
yaml
# Dependency audit in the pipeline
- name: Dependency audit
run: |
npm audit --audit-level=high
# Fail if high or critical vulnerabilities are found
Den lagdelte sikkerhedsmodel placerer hurtig, mønsterbaseret SAST (Semgrep) på hver PR for øjeblikkelig feedback fra udviklerne og dyb semantisk SAST (CodeQL) planlagt for grundig dækning. Afhængighedsscanning kører på hver build, fordi nye CVE'er udgives dagligt.
Almindelige integrationsfejl og hvordan man undgår dem
Kører kun analyse på hovedgrenen. Værdien af statisk analyse er at fange problemer, før de flettes sammen, ikke bagefter. Analyse, der kun kører efter flettet, fungerer som en rapport, ikke en portal.
Indstilling af kvalitetsporte til at advare i stedet for at fejle. En advarsel, der ikke blokerer pipelinen, er en notifikation, som udviklere lærer at ignorere. Gates, der ikke fejler, opbygger ingen kvalitetskultur.
Ikke udelukkelse af testfiler fra dækningstærskler. Test af anden testkode producerer oppustede dækningstal. Udelad testmapper fra dækningsberegninger for at få nøjagtige målinger af produktionskodens dækning.
Ignorerer analyseefterslæbet på ældre kodebaser. At aktivere SonarQube for første gang på en million-linjers ældre kodebase og få 40,000 problemer er demotiverende og kontraproduktivt. Brug den nye kodebaserede tilgang: definer en startdato for "ny kode", anvend kun gates på kode skrevet efter denne dato, og behandl den eksisterende problemopgørelse som et separat program til reduktion af teknisk gæld.
Resultaterne overføres ikke til pull request-kommentarer. Analyseresultater, der er postet på et separat dashboard, som udviklere skal besøge, ignoreres. Analyseresultater, der er postet som indlejrede kommentarer på de specifikke linjer, der forårsagede problemer, i pull request-gennemgangsgrænsefladen, behandles. sonar.pullrequest.* parametre til GitHub-, GitLab- eller Bitbucket-integration, så resultaterne vises der, hvor kodegennemgangen finder sted.
Hvordan SMART TS XL Integrerer med CI/CD-pipelines
De fleste statiske analyseværktøjer i CI/CD-pipelines ser ét sprog ad gangen. ESLint ser JavaScript. SonarQube ser Java, Python, JavaScript og C#. Ingen af dem ser COBOL, JCL, RPG eller de tværsprogsafhængigheder, der forbinder et mainframe-batchprogram til den Java-mikroservice, der forbruger dets output, som forbinder til den JavaScript-frontend, der viser det.
SMART TS XL integreres i CI/CD-pipelines som et tværsproget statisk analyselag, der dækker alle sprog i virksomhedsmiljøet samtidigt. Når en Java-tjeneste ændres, SMART TS XL's konsekvensanalyse sporer afhængighedsgrafen for at identificere, hvilke COBOL-programmer, databaseskemaer og downstream-tjenester der er påvirket af den pågældende ændring, før ændringen implementeres. Når en COBOL-kopibog ændres, identificerer den alle programmer på tværs af hele applikationsporteføljen, der inkluderer den pågældende kopibog og som skal valideres.
Denne bevidsthed om tværsproglig afhængighed er den evne, der gør SMART TS XL's CI/CD-integration er anderledes end at tilføje et andet sprog til SonarQube. Det handler ikke kun om at analysere koden i den ændrede fil. Det handler om at forstå, hvad andet i systemet som ændringen vil påvirke, hvilket er den arkitekturanalyse, der bestemmer det sande omfang af en ændring, før den foretages.
For virksomhedsudviklingsteams, der opererer på tværs af både ældre og moderne stakke, SMART TS XL's DevOps-integration Funktionen integrerer denne strukturelle analyse i pipeline-gennemgangsarbejdsgangen, hvilket giver den arkitektoniske synlighed, som sprogspecifikke værktøjer ikke kan levere. Resultatet er kvalitetsporte, der håndhæver standarder ikke kun inden for en sproggrænse, men på tværs af hele systemet, hvilket sikrer, at en ændring i en komponent ikke introducerer uventede fejl i de komponenter, der er afhængige af den.
Statisk analyse som permanent pipelineborger
De teams, der får statisk analyse til at fungere korrekt, behandler den på samme måde, som de behandler test: ikke som en fase, der skal bestås, men som en kontinuerlig praksis, der er indlejret i hver commit. Analysen kører på hver pull request. Resultater fra kvalitetskontrollen vises i takt med kodegennemgangen. Tærsklerne strammes ind, efterhånden som kodebasen forbedres. Nye analysekategorier tilføjes, efterhånden som teamets sikkerheds- og kvalitetsmodenhed vokser.
Skabelonerne til pipeline-konfiguration i denne artikel er udgangspunkter. De specifikke værktøjer, tærskler og gate-betingelser bør kalibreres til projektets sprogstak, risikoprofil og teamets modenhed. Det, der ikke bør variere, er princippet: Analyse, der ikke gate-merges, ændrer ikke adfærd, og adfærd er det, som kodekvalitetsprogrammer forsøger at ændre.