æ¬çªç°å¢ã«å°éããã³ãŒãã¯ãã¹ãŠããããæ£ãããšä¿¡ããŠã³ãããããããã®ã§ããéçã³ãŒãåæã¯ãã³ãŒããå®è¡ããã®ã§ã¯ãªãããã®æ§é ãèªã¿åããããŒã¿ãããŒã远跡ããæ¢ç¥ã®è匱æ§ããã°ãå質éåã®ãã¿ãŒã³ãšæ¯èŒããããšã§ããã®ä¿¡å¿µãæ£ããã£ããã©ãããæ€èšŒããèªååã·ã¹ãã ã§ããåé¡ã¯ãéçã³ãŒãåæãå®è¡ãããã©ããã§ã¯ãªãããã€ãã©ã€ã³ã®ã©ã®æ®µéã§å®è¡ããããã©ã®ããŒã«ã䜿çšããããã©ã®ãããªéŸå€ãé©çšãããããããŠéçºè ããã£ãŒãããã¯ãç¡èŠããã®ã§ã¯ãªããå®éã«å¯Ÿå¿ã§ããããã«ãããã«è¿ éã«ãã£ãŒãããã¯ãæäŸããããšããããšã§ãã
éçè§£æãåãªããã§ãã¯ããã¯ã¹äœæ¥ãšããŠæããå Žåãšãçã®å質ã²ãŒããšããŠæ©èœãããå Žåãšã®éãã¯ãèšå®ã«ãããŸããå®è¡ããŠèª°ãèªãŸãªãã¬ããŒããçæããã ãã®ã¹ãã£ãã¯ãèŠãããã«éããŸãããäžæ¹ãæ°ããªé倧ãªè匱æ§ãçºèŠãããå Žåã«ãã«ãã倱æãããã«ãã¬ããžãéŸå€ãäžåã£ãå Žåã«ããŒãžããããã¯ãããã«ãªã¯ãšã¹ãã®ã¬ãã¥ãŒã€ã³ã¿ãŒãã§ãŒã¹ã§ãã¡ã€ã«ãšè¡ããšã®è©³çްãªãã£ãŒãããã¯ã衚瀺ããå質ã²ãŒãã¯ãæææ±ºå®ãè¡ãããç¬éã«åäœãå€åããã·ã¹ãã ã§ãã
ãã€ãã©ã€ã³ã®ã©ã®æ®µéã§éçè§£æãå®è¡ããã
éçè§£æã¯è€æ°ã®ç®æã§å®è¡ãã¹ãã§ãããããããç°ãªãç®çãæã€ã¹ãã§ãããäžç®æã ãã§å®è¡ãããšç²ç¹ãçããããããç®æã§åçã«å®è¡ãããšãéçºè ãè¿åãããããªäœéãªãã€ãã©ã€ã³ãçæãããã
| ãã€ãã©ã€ã³ã¹ããŒãž | äœãèµ°ãã | ã¬ã€ãã³ã·ãŒããžã§ãã | ç®ç |
|---|---|---|---|
| äºåã³ãããïŒããŒã«ã«ïŒ | é«éãªã³ã¿ãŒã®ã¿ (ESLintãClippyãrustfmt) | 5ç§æªæº | æãããªåé¡ããªããžããªã«åæ ãããåã«é»æ¢ãã |
| ãã«ãªã¯ãšã¹ãïŒããŒãžãªã¯ãšã¹ã | ãã«ãªã³ãã£ã³ã° + SAST + å¢åSonarQubeã¹ãã£ã³ | 3åæªæº | ãããã¯ã¯æ°ããªéèŠèª²é¡ã«ã€ããŠçµ±åãã |
| ã¡ã€ã³ãã©ã³ãã®ãã«ã | ã«ãã¬ããžãéè€ãæè¡çè² åµãå«ã詳现ãªåæ | 10åæªæº | å質ãã¬ã³ãã远跡ããããã·ã¥ããŒããæŽæ°ãã |
| æ¯æ©äºå® | 詳现ã¹ãã£ã³ãäŸåé¢ä¿ç£æ»ãã³ã³ãã©ã€ã¢ã³ã¹ãã§ã㯠| äºç®ãªã | çç£é å»¶åé¡ãšãµãã©ã€ãã§ãŒã³ãªã¹ã¯ãææ¡ãã |
æã䟡å€ã®ããæ®µéã¯ãã«ãªã¯ãšã¹ãã§ãã¡ã€ã³ãã©ã³ããžã®ããã·ã¥æã«å®è¡ãããåæã¯ãããŒãžã®æ±ºå®ãäžãããåŸã«å®è¡ãããŸããäžæ¹ããã«ãªã¯ãšã¹ãæã«å®è¡ãããæ£ç¢ºãªãã¡ã€ã«ãšè¡ã®ã³ã³ããã¹ããå«ãã€ã³ã©ã€ã³ã³ã¡ã³ããæçš¿ããåæã¯ãéçºè ããŸã ã³ãŒãã«åãçµãã§ããæ®µéã§å®è¡ãããä¿®æ£ã³ã¹ããæãäœããªããŸãã
ä¿åã®ãã³ã«ã³ãããåã«å€§èŠæš¡ãªåæãå®è¡ãããšãéçºè ã®ãšã¯ã¹ããªãšã³ã¹ãèããäœäžããŸãã5ç§ä»¥å ã«å®äºããé«éãªãªã³ã¿ãŒã¯å¿ èŠã§ããããã以å€ã¯ãã¹ãŠCIïŒç¶ç¶çã€ã³ãã°ã¬ãŒã·ã§ã³ïŒã§è¡ãã¹ãã§ãã
GitHub Actions: å®å šãªåäœæ§æ
GitHub Actionsã¯ãæãåºãå©çšãããŠããCIãã©ãããã©ãŒã ã§ãã以äžã®ã¯ãŒã¯ãããŒã§ã¯ããã©ãŒããããã§ãã¯ããªã³ãã£ã³ã°ããã«ããSASTã»ãã¥ãªãã£ã¹ãã£ã³ãSonarCloudå質ã²ãŒããšãã£ããéå±€åãããå質ãã€ãã©ã€ã³ãå®è¡ããŸãã
ã€ã ã«
# .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 }}
ããããã£
# 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
ãã®ã¯ãŒã¯ãããŒã«ãããéèŠãªæ§æäžã®æ±ºå®äºé ïŒ
--max-warnings 0ESLintã§ã¯ãã©ããªèŠåããã«ãã®å€±æãšã¿ãªãããŸããèŠåã蚱容ããããŒã ã¯ã誰ãèªãŸãªããªããŸã§èŠåãèç©ãç¶ããŸããfetch-depth: 0ãã§ãã¯ã¢ãŠãæ: SonarCloud ã¯ãçºçããåé¡ã®åå ãç¹å®ããæ°èŠã³ãŒã ã¡ããªã¯ã¹ãæ£ããèšç®ããããã«ãå®å šãª Git å±¥æŽãå¿ èŠãšããŸãã- Semgrepã¯lintã®åŸã«SonarãšäžŠè¡ããŠå®è¡ãããŸããã»ãã¥ãªãã£ãšå質ã®ã¹ãã£ã³ã¯ç¬ç«ããæžå¿µäºé ã§ããããããããã䞊è¡ããŠå®è¡ããããšã§ãã€ãã©ã€ã³å šäœã®æéãççž®ã§ããŸãã
- ãã¹ãã¯ä»¥äžã§å®è¡ãããŸã
lcovã«ãã¬ããžåºåïŒSonarCloudã¯ãã®åºåãèªã¿åãããã¡ã€ã«ããšã®ã«ãã¬ããžã衚瀺ããå質ã²ãŒãã§ã«ãã¬ããžã®ãããå€ãé©çšããŸãã
GitLab CI/CDïŒå質ã²ãŒããåããå質ãã€ãã©ã€ã³
ã€ã ã«
# .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: ãã®ãããã¯ã¯ãSemgrepããã®SARIFåºåãGitLabã®ã»ãã¥ãªãã£ããã·ã¥ããŒãã«çŽæ¥çµ±åããæ€åºçµæãçã®CIãã°åºåãšããŠã§ã¯ãªããããŒãžãªã¯ãšã¹ãã®ã»ãã¥ãªãã£ã¬ããŒãã«è¡šç€ºããŸãã
Jenkins: SonarQubeã䜿çšãã宣èšåãã€ãã©ã€ã³
ã°ã«ãŒããŒ
// 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 ããã¯éèŠãªè¡ã§ããåæãå®äºãããŸã§SonarQubeãããŒãªã³ã°ããå質ã²ãŒããæºããããªãå Žåã¯ãã«ãã倱æãããŸããããããªããšãåæããŸã å®è¡äžã®ç¶æ
ã§ãã€ãã©ã€ã³ãå®äºããå質ã²ãŒãã®çµæãé©çšãããªããªããŸãã
ããŒã ãå®éã«å°éããå質ã²ãŒããèšå®ãã
ãããå€ã®èšå®ãå³ããããããã«ã³ãããããšã«å€±æããå質ã²ãŒãã¯ç¡å¹åããããäžæ¹ããããå€ãç·©ãããããã«æ±ºããŠå€±æããªãå質ã²ãŒãã¯äŸ¡å€ããªããç®æšã¯ããããžã§ã¯ãã®å®éã®ãªã¹ã¯ãããã¡ã€ã«ã«åãããŠèª¿æŽãããã²ãŒããèšå®ããããšã§ããã
SonarQubeå質ã²ãŒããæ°èŠã«å°å ¥ããéã®æšå¥šåæèšå®ïŒ
| ã¡ããªã㯠| ç¶æ | ãããå€ |
|---|---|---|
| æ°ãããã° | è¶ãã | 0 |
| æ°ããªèåŒ±æ§ | è¶ãã | 0 |
| æ°ããªã»ãã¥ãªãã£äžã®ãããã¹ããããæ€èšŒ | ä»¥äž | 100% |
| æ°ããã³ãŒãã«ãã¬ããž | ä»¥äž | 80% |
| æ°ããéè€è¡ | è¶ãã | 3% |
| æ°ããã³ãŒãã®èã | è¶ãã | 10 |
ãããã®ãããå€ãé©çšã㊠æ°ããã³ãŒãã®ã¿ ïŒSonarQubeã®ãæ°èŠã³ãŒããæéïŒãã¬ã¬ã·ãŒãããžã§ã¯ãã®ã³ãŒãããŒã¹å šäœã«é©çšããªãã§ãã ããã5幎éèç©ãããæè¡çè² åµã®ããã«ãã«ããæ¯å倱æãããšãããŒã ã¯ã²ãŒããå®å šã«ç¡å¹ã«ããŠããŸãå¯èœæ§ããããŸããæ°èŠã³ãŒãã¢ãããŒãã§ã¯ãæ¢åã®è² åµãå¥éåŠçããªãããåé¡ã®çºçãé£ãæ¢ããããšãã§ããŸãã
æéçµéã«äŒŽãã©ãã§ããéŸå€ã®å€åã ãŸãã¯æ§ãããªåºæºå€ãèšå®ããããŒã ãããã¯ãã°ãè§£æ¶ããŠããã«ã€ããŠãååæããšã«åºæºå€ãå³ããããŠãããäŸãã°ãçŸåš75%ã®ã«ããŒçã§åæ ŒããŠããã²ãŒãã¯ãããŒã¹ã©ã€ã³ã80%ãååã«äžåã£ãæç¹ã§ã80%ã«åŒãäžããããšãã§ãããæ®µéçã«åºæºå€ãå³ããããŠããæ¹ãããããªãå®ç§ãç®æããããæç¶å¯èœã ã
å€§èŠæš¡ã³ãŒãããŒã¹ã«ãããéçè§£æããã©ãŒãã³ã¹ã®åŠç
ããŒã ãCIã§éçè§£æãç¡å¹åãããåé¿ãããããæãäžè¬çãªçç±ã¯ããã€ãã©ã€ã³ã®åŠçé床ãé ããªããããããã§ãããã£ãŒãã£ãŒãã©ã³ããžã®ããã·ã¥ããšã«15åãã®å質ã¹ãã£ã³ãå®è¡ãããšãéçºè ã®äœæ¥ãããŒãé»å®³ãããŸããè§£æãé«éåããããã®æŠç¥ã¯ããã€ããããŸãã
å¢ååæïŒæ°èŠã³ãŒãã®ã¿ïŒã SonarQube ããã³ã»ãšãã©ã®ãšã³ã¿ãŒãã©ã€ãºéçè§£æããŒã«ã¯ãã³ãŒãããŒã¹å
šäœã§ã¯ãªãããã«ãªã¯ãšã¹ãå
ã®å€æŽããããã¡ã€ã«ã®ã¿ãåæããããšããµããŒãããŠããŸãã sonar.pullrequest.base, sonar.pullrequest.branch, sonar.pullrequest.key PRåºæã®å¢åã¹ãã£ã³ãæå¹ã«ãããã©ã¡ãŒã¿ãã¡ã€ã³ãã©ã³ããžã®ããŒãžæã«ã¯åŒãç¶ããã«åæãå®è¡ãããŸããPRã¹ãã£ã³ã¯ã»ãšãã©ã®ã³ãŒãããŒã¹ã§2å以å
ã«å®äºããŸãã
ãã£ãã·ã³ã°ã å€ãã®éçè§£æå®è¡ã«ãããŠæãã³ã¹ãããããã®ã¯ãããŒã«ãšãã®ã«ãŒã«å®çŸ©ã®ããŠã³ããŒãã§ããã¹ãã£ããŒãã€ããªãã«ãŒã«ããŒã¿ããŒã¹ãããã³è§£æ±ºæžã¿ã®äŸåé¢ä¿ããå®è¡éã§ãã£ãã·ã¥ããŠãã ããã
ã€ã ã«
# 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
äžŠåæ§é ã ãªã³ãã£ã³ã°ãã»ãã¥ãªãã£ã¹ãã£ã³ãå質ã²ãŒãåæã¯ããããç¬ç«ããåŠçã§ãããããã¯é 次å®è¡ããã®ã§ã¯ãªãã䞊åã§å®è¡ããŠãã ããããã€ãã©ã€ã³å šäœã®å®è¡æéã¯ããã¹ãŠã®ãžã§ãã®åèšã§ã¯ãªããæãæéã®ããããžã§ãã«ãã£ãŠæ±ºãŸããŸãã
éžæçãªããŒã«èµ·åã ãã¹ãŠã®ããŒã«ããã¹ãŠã®ãã©ã³ãã§å®è¡ããå¿ èŠã¯ãããŸããããã«ãªã¯ãšã¹ããšã¡ã€ã³ãã©ã³ãã§ã¯å®å šãªã»ãã¥ãªãã£ã¹ãã£ã³ãšã³ã³ãã©ã€ã¢ã³ã¹ãã§ãã¯ãå®è¡ããããŒãžåã®ãã©ã³ãã§ã¯é«éãªã³ã¿ãŒã®ã¿ãå®è¡ã§ããŸããCIæ§æã§ãã©ã³ããã£ã«ã¿ã䜿çšããŠãç°ãªãåæãããã¡ã€ã«ãé©çšããŠãã ããã
ã»ãã¥ãªãã£åªå ãã€ãã©ã€ã³ã«ãããéçè§£æïŒSASTãšäŸåé¢ä¿ã¹ãã£ã³
ã»ãã¥ãªãã£éèŠã®ãã€ãã©ã€ã³ã¯ãæšæºçãªå質åæã«å ããŠãã¢ããªã±ãŒã·ã§ã³ã³ãŒãã®è匱æ§ãæ€åºããããã®SASTïŒéçã¢ããªã±ãŒã·ã§ã³ã»ãã¥ãªãã£ãã¹ãïŒãšããµãŒãããŒãã£ã©ã€ãã©ãªã«ãããæ¢ç¥ã®CVEïŒå ±éè匱æ§èå¥åïŒãæ€åºããããã®äŸåé¢ä¿ã¹ãã£ã³ãšãã2ã€ã®ã¬ã€ã€ãŒã远å ããŸãã
SASTããŒã« (SemgrepãCodeQLãSnyk CodeãCheckmarx)ã¯ãä¿¡é Œã§ããªãããŒã¿ãã¢ããªã±ãŒã·ã§ã³ã³ãŒããã©ã®ããã«æµããŠæ©å¯æ§ã®é«ãæäœã«å°éããããåæããŸãããããã®ããŒã«ã¯ãæšæºçãªå質ã®ãªã³ã¿ãŒã§ã¯æ€åºã§ããªãSQLã€ã³ãžã§ã¯ã·ã§ã³ãXSSãã³ãã³ãã€ã³ãžã§ã¯ã·ã§ã³ãå®å šã§ãªãéã·ãªã¢ã«åãããŒãã³ãŒããããèªèšŒæ å ±ãªã©ãæ€åºããŸãã
ã€ã ã«
# 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"
äŸåé¢ä¿ã¹ãã£ã³ ãã§ã㯠package.json, pom.xml, requirements.txtãããã³è匱æ§ããŒã¿ããŒã¹ã«å¯Ÿããåçã®ãããã§ã¹ããã¡ã€ã«ïŒ
ã€ã ã«
# Dependency audit in the pipeline
- name: Dependency audit
run: |
npm audit --audit-level=high
# Fail if high or critical vulnerabilities are found
éå±€åã»ãã¥ãªãã£ã¢ãã«ã§ã¯ãéçºè ãžã®å³æãã£ãŒãããã¯ã®ããã«ããã¹ãŠã®ãã«ãªã¯ãšã¹ãã«å¯ŸããŠé«éãªãã¿ãŒã³ããŒã¹ã®SASTïŒSemgrepïŒãå®è¡ãã培åºçãªã«ãã¬ããžã®ããã«å®æçã«è©³çްãªã»ãã³ãã£ãã¯SASTïŒCodeQLïŒãå®è¡ããŸããæ°ããCVEãæ¯æ¥å ¬éããããããäŸåé¢ä¿ã®ã¹ãã£ã³ã¯ãã¹ãŠã®ãã«ãã§å®è¡ãããŸãã
ããããçµ±åãã¹ãšãã®åé¿æ¹æ³
ã¡ã€ã³ãã©ã³ãã®ã¿ã§åæãå®è¡ããŸãã éçè§£æã®ç䟡ã¯ãããŒãžåŸã§ã¯ãªããããŒãžåã«åé¡ãæ€åºããããšã«ãããããŒãžåŸã«ã®ã¿å®è¡ãããè§£æã¯ãã²ãŒãã§ã¯ãªãã¬ããŒããšããŠã®åœ¹å²ããæãããªãã
å質ã²ãŒããã倱æã§ã¯ãªãèŠåãçºããããã«èšå®ããã ãã€ãã©ã€ã³ããããã¯ããªãèŠåã¯ãéçºè ãç¡èŠããããã«ãªãéç¥ã«éããªãã倱æããªãã²ãŒãã¯ãå質æåãè²ãŸãªãã
ãã¹ããã¡ã€ã«ãã«ãã¬ããžãããå€ããé€å€ããªãã ãã¹ãã³ãŒããå¥ã®ãã¹ãã³ãŒãããã¹ããããšãã«ãã¬ããžã®æ°å€ãé倧è©äŸ¡ãããŸããæ¬çªã³ãŒãã®ã«ãã¬ããžãæ£ç¢ºã«æž¬å®ããã«ã¯ããã¹ããã£ã¬ã¯ããªãã«ãã¬ããžèšç®ããé€å€ããŠãã ããã
æ¢åã³ãŒãããŒã¹ã«é¢ããåæã®ããã¯ãã°ãç¡èŠããã 100äžè¡ã«ãåã¶æ¢åã®ã³ãŒãããŒã¹ã§åããŠSonarQubeãèµ·åãã4äžä»¶ãã®èª²é¡ãèŠã€ããã®ã¯ãã¢ãããŒã·ã§ã³ãäœäžãããé广ã§ããæ°èŠã³ãŒãããŒã¹ã©ã€ã³ã¢ãããŒããæ¡çšããŸãããããæ°èŠã³ãŒããã®éå§æ¥ãå®çŸ©ãããã®æ¥ä»¥éã«æžãããã³ãŒãã«ã®ã¿ã²ãŒããé©çšããæ¢åã®èª²é¡ããã¯ãã°ã¯å¥ã®æè¡çè² åµåæžããã°ã©ã ãšããŠæ±ããŸãã
çµæããã«ãªã¯ãšã¹ãã®ã³ã¡ã³ãã«æžã蟌ãŸãªãã éçºè
ãã¢ã¯ã»ã¹ããå¿
èŠã®ããå¥ã®ããã·ã¥ããŒãã«æçš¿ãããåæçµæã¯ç¡èŠãããŸãããã«ãªã¯ãšã¹ãã¬ãã¥ãŒã€ã³ã¿ãŒãã§ãŒã¹å
ã§ãåé¡ãåŒãèµ·ãããç¹å®ã®è¡ã«ã€ã³ã©ã€ã³ã³ã¡ã³ããšããŠæçš¿ãããåæçµæã¯å¯ŸåŠãããŸããèšå® sonar.pullrequest.* GitHubãGitLabããŸãã¯Bitbucketãšã®é£æºã«é¢ãããã©ã¡ãŒã¿ãèšå®ããããšã§ãã³ãŒãã¬ãã¥ãŒãè¡ãããå Žæã«çºèŠäºé
ã衚瀺ãããããã«ãªããŸãã
èªå®æ¡ä»¶ SMART TS XL CI/CDãã€ãã©ã€ã³ãšçµ±å
CI/CDãã€ãã©ã€ã³ã§äœ¿çšãããéçè§£æããŒã«ã®ã»ãšãã©ã¯ãäžåºŠã«1ã€ã®èšèªããèªèããŸãããESLintã¯JavaScriptãèªèããŸããSonarQubeã¯JavaãPythonãJavaScriptãC#ãèªèããŸããããããCOBOLãJCLãRPGããããã¯ã¡ã€ã³ãã¬ãŒã ã®ãããããã°ã©ã ãšããã®åºåãåŠçããJavaãã€ã¯ããµãŒãã¹ããããŠããã衚瀺ããJavaScriptããã³ããšã³ããæ¥ç¶ãããããªãèšèªéã®äŸåé¢ä¿ã¯ããããã®ããŒã«ã§ã¯èªèãããŸããã
SMART TS XL CI/CD ãã€ãã©ã€ã³ã«ãäŒæ¥ç°å¢ã®ãã¹ãŠã®èšèªãåæã«ã«ããŒããã¯ãã¹èšèªéçè§£æã¬ã€ã€ãŒãšããŠçµ±åãããŸããJava ãµãŒãã¹ã倿Žããããšã SMART TS XLãã 圱é¿åæ 倿Žãå±éãããåã«ãäŸåé¢ä¿ã°ã©ãããã¬ãŒã¹ããŠãã©ã® COBOL ããã°ã©ã ãããŒã¿ããŒã¹ ã¹ããŒããããã³äžæµãµãŒãã¹ããã®å€æŽã®åœ±é¿ãåããããç¹å®ããŸããCOBOL ã³ããŒããã¯ã倿Žããããšããã®ã³ããŒããã¯ãå«ãã¢ããªã±ãŒã·ã§ã³ ããŒããã©ãªãªå šäœã«ããããæ€èšŒãå¿ èŠãªãã¹ãŠã®ããã°ã©ã ãç¹å®ããŸãã
ãã®èšèªéã®äŸåé¢ä¿ã®èªèã¯ã SMART TS XLã® CI/CD çµ±åã¯ãSonarQube ã«å¥ã®èšèªã远å ããã®ãšã¯ç°ãªããŸãã倿Žããããã¡ã€ã«ã®ã³ãŒããåæããã ãã§ã¯ãªãããã®å€æŽãã·ã¹ãã å ã®ä»ã®éšåã«ã©ã®ãããªåœ±é¿ãäžããããçè§£ããããšãéèŠã§ããã€ãŸãã倿Žãè¡ãåã«ã倿Žã®çã®ç¯å²ã決å®ããã¢ãŒããã¯ãã£åæãè¡ãå¿ èŠãããã®ã§ãã
ã¬ã¬ã·ãŒã¹ã¿ãã¯ãšã¢ãã³ã¹ã¿ãã¯ã®äž¡æ¹ã§éçšãããšã³ã¿ãŒãã©ã€ãºéçºããŒã ã®å Žåã SMART TS XLãã DevOpsçµ±å ãã®æ©èœã¯ãæ§é åæããã€ãã©ã€ã³ã¬ãã¥ãŒã®ã¯ãŒã¯ãããŒã«çµã¿èŸŒãããšã§ãèšèªåºæã®ããŒã«ã§ã¯å®çŸã§ããªãã¢ãŒããã¯ãã£ã®å¯èŠæ§ãæäŸããŸãããã®çµæãèšèªã®å¢çå ã ãã§ãªãã·ã¹ãã å šäœã«ããã£ãŠæšæºã匷å¶ããå質ã²ãŒããæ§ç¯ãããããããã®ã³ã³ããŒãã³ãã®å€æŽããããã«äŸåããã³ã³ããŒãã³ãã«äºæãã¬é害ãåŒãèµ·ãããªãããšãä¿èšŒãããŸãã
éçè§£æããã€ãã©ã€ã³ã®æä¹ çãªæ§æèŠçŽ ãšããŠäœçœ®ã¥ãã
éçè§£æãæ£ããå®è·µããŠããããŒã ã¯ããã¹ããšåæ§ã«ãéçè§£æãåãªãééç¹ãšããŠã§ã¯ãªãããã¹ãŠã®ã³ãããã«çµã¿èŸŒãŸããç¶ç¶çãªå®è·µãšããŠæããŠããŸããè§£æã¯ãã¹ãŠã®ãã«ãªã¯ãšã¹ãã§å®è¡ãããå質ã²ãŒãã®çµæã¯ã³ãŒãã¬ãã¥ãŒãšé£åããŠè¡šç€ºãããŸããã³ãŒãããŒã¹ã®æ¹åã«äŒŽãããããå€ã¯å³ãããªããããŒã ã®ã»ãã¥ãªãã£ãšåè³ªã®æç床ãé«ãŸãã«ã€ããŠãæ°ããªè§£æã«ããŽãªã远å ãããŸãã
ãã®èšäºã§ç޹ä»ãããã€ãã©ã€ã³æ§æãã³ãã¬ãŒãã¯ãããŸã§åºçºç¹ã§ããå ·äœçãªããŒã«ããããå€ãã²ãŒãæ¡ä»¶ã¯ããããžã§ã¯ãã®èšèªã¹ã¿ãã¯ããªã¹ã¯ãããã¡ã€ã«ãããŒã ã®æç床ã«åãããŠèª¿æŽããå¿ èŠããããŸãããã ãã以äžã®ååã¯å€ããŠã¯ãªããŸãããããŒãžãã²ãŒãããªãåæã¯åäœãå€ãããã³ãŒãå質ããã°ã©ã ãå€ããããšããŠããã®ã¯ãŸãã«ãã®åäœãªã®ã§ãã