Jenkins Learn
04. Jenkins Pipeline

Environment & Parameters

Khai báo, phân phạm vi và kiểm soát environment cùng parameters trong Jenkinsfile Declarative.

Phạm vi và giả định

Bài này dùng Declarative Pipeline trên Jenkins có plugin Pipeline: Declarative. Mẫu cần một agent Unix mang label linux và step sh; withEnv là Pipeline step do các plugin Pipeline cung cấp. Credential binding được nhắc ở mức tham chiếu và cần plugin Credentials Binding cùng credential đã được quản trị sẵn. Không có ví dụ nào kết nối, deploy hoặc dùng secret thật.

environment là cấu hình runtime không nhạy cảm của Pipeline, còn parameters là input lúc khởi tạo build. Cả hai làm Jenkinsfile linh hoạt hơn, nhưng không phải quyền truy cập: một giá trị được chọn không tự cho phép job chạm production, gọi hostname hoặc chạy lệnh tùy ý.

Mục lục

Hai namespace env và params

env: biến môi trường của process

env là đối tượng Pipeline để đọc hoặc, trong các trường hợp phù hợp, đặt biến môi trường. Jenkins cũng đặt sẵn nhiều biến như BUILD_NUMBER, JOB_NAME, WORKSPACE và BRANCH_NAME khi ngữ cảnh cung cấp chúng. Khi gọi sh, các biến đang hiệu lực được truyền vào process shell; shell Unix đọc chúng bằng $NAME.

Dùng env cho cấu hình mà process cần biết, chẳng hạn tên ứng dụng, log level hoặc mã định danh build. Không dùng env làm kho secret trong Git. Với biến do environment {} khai báo, giá trị nên là hằng không nhạy cảm hoặc tham chiếu credential đã quản trị; chi tiết binding nằm ở Credentials trong Pipeline.

params: input của build

params chứa các parameter mà người dùng hoặc trigger đã chọn cho lần build hiện tại. Trong Declarative Pipeline, đọc chúng qua params.TÊN, ví dụ params.DEPLOY_TIER. params khác env: parameter là dữ liệu điều khiển flow, không phải lời hứa rằng process shell sẽ nhận được biến cùng tên trên mọi loại job/plugin.

Dùng parameter cho lựa chọn nhỏ, đã định nghĩa trước, rồi kiểm tra/map lại trước hành động có side effect. choice cho phép Jenkins UI giới hạn lựa chọn, nhưng Jenkinsfile vẫn nên có allowlist khi giá trị chuẩn bị đi vào logic nhạy cảm. string là input tự do hơn nên phải có giới hạn độ dài/định dạng và không được đưa thẳng vào shell, URL, hostname, path hay câu lệnh.

Parameter không phải authorization

Quyền Build, quyền dùng credential, policy môi trường, quyền ở hệ thống đích và approval là các kiểm soát riêng. Người chọn production không vì thế được cấp token production hay được phép deploy. Đừng dùng parameter để nhận một command, IP, hostname hoặc URL tùy ý.

Khai báo environment và parameters

Pipeline-level và stage-level environment

environment ở cấp pipeline áp dụng cho các stage. environment bên trong một stage chỉ áp dụng khi stage đó chạy và có thể đặt giá trị cùng tên để chuyên biệt hóa giá trị pipeline-level cho stage này.

pipeline {
  agent any

  environment {
    APP_NAME = 'inventory-api'
    LOG_LEVEL = 'info'
  }

  stages {
    stage('Package') {
      environment {
        LOG_LEVEL = 'debug'
      }
      steps {
        sh 'printf "%s\\n" "$APP_NAME:$LOG_LEVEL"'
      }
    }
  }
}

Trong stage Package, output là inventory-api:debug; ngoài stage đó, LOG_LEVEL trở lại info. agent any chỉ giúp ví dụ ngắn; Pipeline thật nên chọn label/toolchain và trust boundary rõ ràng như giải thích ở Declarative Pipeline.

String, boolean và choice parameters

Khai báo parameters ở cấp pipeline, không đặt trong steps. Ba loại dưới đây có vai trò khác nhau:

LoạiVí dụCách dùng an toàn
stringRELEASE_NOTEGiới hạn độ dài/format; chỉ dùng làm metadata sau validation, không ghép vào command.
booleanParamDRY_RUNDùng như boolean rõ ràng trong when hoặc script; không dựa vào chuỗi không rỗng.
choiceDEPLOY_TIERDanh sách hẹp như staging, production; map sang hành vi/đích cố định do đội vận hành quản lý.

Lần đầu Jenkins chạy một Jenkinsfile mới có parameters, UI của một số job có thể chưa hiện Build with Parameters cho đến khi build đầu tiên đã lưu properties của job. Chạy lần đầu trên branch/job lab, xác nhận parameter và default trong UI rồi mới dùng nó trong flow quan trọng.

Scope, override và precedence

Bản đồ scope

Sơ đồ này mô tả thứ tự các scope bao quanh một sh trong stage. Scope gần process hơn có thể che cùng tên biến từ scope ngoài trong thời gian nó còn hiệu lực.

direction: down
baseline: Jenkins/controller, node hoặc agent env
pipeline: "Pipeline-level environment\nAPP_NAME, LOG_LEVEL=info"
stage: "Stage-level environment\nLOG_LEVEL=debug"
overlay: "withEnv\nLOG_LEVEL=trace"
process: Shell đọc APP_NAME và LOG_LEVEL=trace
params: "params.DEPLOY_TIER\nnamespace riêng, chỉ dùng khi\nJenkinsfile đọc nó"
baseline -> pipeline -> stage -> overlay -> process
Jenkins/controller, node hoặc agent envPipeline-level environmentAPP_NAME, LOG_LEVEL=infoStage-level environmentLOG_LEVEL=debugwithEnvLOG_LEVEL=traceShell đọc APP_NAME và LOG_LEVEL=traceparams.DEPLOY_TIERnamespace riêng, chỉ dùng khiJenkinsfile đọc nó
Jenkins/controller, node hoặc agent envPipeline-level environmentAPP_NAME, LOG_LEVEL=infoStage-level environmentLOG_LEVEL=debugwithEnvLOG_LEVEL=traceShell đọc APP_NAME và LOG_LEVEL=traceparams.DEPLOY_TIERnamespace riêng, chỉ dùng khiJenkinsfile đọc nó
Bản đồ scope
Nguồn giá trịPhạm vi điển hìnhThời điểm hết hiệu lựcDùng cho
Environment của controller/node/agentAgent hoặc process kế thừaKhi process/agent kết thúc hoặc cấu hình đổiToolchain, PATH, metadata hạ tầng; không xem là source cấu hình ứng dụng đáng tin cậy.
Jenkins built-in environmentBuild hoặc stage theo ngữ cảnhHết build/stageBUILD_NUMBER, WORKSPACE, metadata branch khi plugin/job cung cấp.
Pipeline-level environmentToàn PipelineKết thúc PipelineHằng cấu hình chung không nhạy cảm.
Stage-level environmentMột stageStage kết thúcChuyên biệt hóa cấu hình cho một chặng.
withEnv([...])Closure/blockThoát blockOverride tạm, cục bộ quanh một hoặc vài step.
paramsBuild hiện tại, nhưng namespace riêngKết thúc buildLựa chọn/input để Jenkinsfile quyết định flow.

Quy tắc precedence

Khi cùng tên biến môi trường xuất hiện ở các scope trên, áp dụng các quy tắc thực hành sau:

  1. Giá trị stage-level che giá trị cùng tên ở pipeline-level trong stage đó.
  2. withEnv bên trong stage che giá trị từ pipeline-level lẫn stage-level trong closure của nó. Khi closure kết thúc, giá trị stage-level có hiệu lực lại.
  3. Biến được khai báo bằng Declarative environment không nên bị sửa bằng phép gán imperative env.NAME = '...'. Jenkins bảo vệ giá trị Declarative theo cách này; dùng withEnv khi cần override tạm.
  4. Biến do code tạo bằng env.NAME = '...' có thể bị ghi đè bởi một phép gán env sau đó, nhưng cách này làm provenance khó thấy hơn. Chỉ dùng cho giá trị runtime đã validate và ưu tiên một tên mới, ví dụ RUN_SUMMARY, thay vì đổi hằng cấu hình như APP_NAME.
  5. params.NAME không tham gia precedence của env.NAME. Nếu tên trùng nhau, chúng vẫn là hai namespace khác; đọc đúng namespace và đừng dựa vào việc plugin có export parameter thành environment hay không.

Không dùng precedence để vượt policy. Một withEnv có thể đổi LOG_LEVEL cho test, nhưng không được dùng để tự nạp credential, đổi endpoint sang host do user nhập, hay giả mạo biến mà tool security dựa vào.

withEnv cho override ngắn hạn

withEnv phù hợp khi một process riêng cần biến khác mà không muốn làm rò giá trị sang step kế tiếp. Đây là một Pipeline step, nên availability cụ thể phụ thuộc bộ plugin Pipeline của controller; kiểm tra Pipeline Syntax trên chính Jenkins của bạn.

Diff chỉ thay scope của lệnh diagnostic: bản trước đọc debug, bản sau tạm đọc trace. Cả hai vẫn kiểm tra debug ở step kế tiếp. Đây là fragment stage, đặt bên trong stages của Declarative Pipeline.

Override LOG_LEVEL chỉ trong một block
2 dòng không đổi
Giữ; trước 1; sau 1; stage('Diagnostic an toàn') {
Giữ; trước 2; sau 2; environment {
Giữ; trước 3; sau 3; LOG_LEVEL = 'debug'
Giữ; trước 4; sau 4; }
Giữ; trước 5; sau 5; steps {
Xóa; trước 6; sh '''
Xóa; trước 7; set -eu
Xóa; trước 8; printf '%s\n' "inside=$LOG_LEVEL"
Xóa; trước 9; '''
Thêm; sau 6; withEnv(['LOG_LEVEL=trace']) {
Thêm; sau 7; sh '''
Thêm; sau 8; set -eu
Thêm; sau 9; printf '%s\n' "inside=$LOG_LEVEL"
Thêm; sau 10; '''
Thêm; sau 11; }
Giữ; trước 10; sau 12; sh 'test "$LOG_LEVEL" = "debug"'
Giữ; trước 11; sau 13; }
Giữ; trước 12; sau 14; }

Trong block, shell nhận trace; sau block, test xác nhận stage-level debug đã trở lại. Dùng triple single quote cho script nhiều dòng để Groovy không nội suy $LOG_LEVEL trước shell. Việc quote đúng không làm input không tin cậy an toàn: giải pháp chính vẫn là không đưa input tự do vào script.

Khi nào giá trị được resolve?

Giá trị tĩnh và giá trị dynamic

Jenkins parse cấu trúc Declarative trước khi thực thi flow. Khi người dùng khởi tạo build, parameter được chọn rồi Pipeline đọc qua params. Giá trị environment có scope tương ứng khi Jenkins đi vào Pipeline/stage/block đó; built-in như BUILD_NUMBER và WORKSPACE chỉ có ý nghĩa khi Jenkins đã tạo build hoặc cấp agent/workspace phù hợp.

Giá trị tĩnh nên nằm trực tiếp trong environment, ví dụ APP_NAME = 'inventory-api'. Đừng cố gọi shell để “tính động” trong top-level environment: việc đó phụ thuộc thứ tự cấp agent, workspace và version/plugin, có thể làm lúc parse hoặc lúc cấp agent khó đoán hơn. Nếu giá trị cần command hoặc metadata runtime, tính nó sau khi stage đã có agent, trong script {} hoặc step rõ ràng.

Với when chỉ đọc parameter/metadata, thêm beforeAgent true để Jenkins quyết định trước khi giữ executor. Xem Điều kiện when và phê duyệt input để biết thứ tự when, input và stage agent.

Tính dynamic value trong script an toàn

Dynamic value là dữ liệu chỉ biết khi build đang chạy, ví dụ build number hoặc kết quả một phép map đã review. Mẫu an toàn là: lấy input có giới hạn, kiểm tra allowlist, map sang giá trị cố định, rồi đặt một biến mới cho những step tiếp theo. Không chạy Groovy hay shell do parameter cung cấp.

script {
  def tiers = [
    'staging': 'STAGING',
    'production': 'PRODUCTION',
  ]
  def selectedTier = tiers[params.DEPLOY_TIER]

  if (selectedTier == null) {
    error('DEPLOY_TIER is not allowlisted')
  }

  def mode = params.DRY_RUN ? 'dry-run' : 'preview'
  env.RUN_SUMMARY = "${selectedTier}-${mode}-${env.BUILD_NUMBER}"
}

RUN_SUMMARY chỉ được tạo từ map cố định, boolean và BUILD_NUMBER do Jenkins tạo. Step sh sau đó có thể đọc $RUN_SUMMARY mà không cần nội suy params vào script. Nếu dynamic value thật sự cần gọi tool, gọi một command cố định, lấy output qua sh(returnStdout: true, script: '...').trim(), kiểm tra format/allowlist/độ dài trước khi lưu và không làm điều này trong scope có secret trừ khi bắt buộc.

Dynamic không đồng nghĩa an toàn

script {} cho phép Groovy linh hoạt hơn Declarative, nên validator khó mô hình hóa flow bên trong hơn. Giữ block ngắn, deterministic, không có side effect; đưa logic lặp lại hoặc phức tạp vào Shared Library đã review. Một output từ shell, API, SCM hay parameter vẫn là dữ liệu không tin cậy cho đến khi được validate.

Jenkinsfile mẫu an toàn

Mẫu này có string, boolean và choice parameter; environment tĩnh ở hai scope; withEnv; và một dynamic value tính trong script. Nó chỉ in metadata đã kiểm soát và không checkout, deploy, gọi network hay dùng credential. Cần Declarative Pipeline và agent Unix linux; sh là step Unix. Đổi label theo agent lab thực tế, không chuyển workload không tin cậy sang controller để mẫu chạy được.

pipeline {
  agent none

  parameters {
    string(
      name: 'RELEASE_NOTE',
      defaultValue: '',
      trim: true,
      description: 'Metadata tối đa 120 ký tự; không được đưa vào shell hoặc hostname.'
    )
    booleanParam(
      name: 'DRY_RUN',
      defaultValue: true,
      description: 'Chỉ chọn chế độ mô phỏng đã định nghĩa.'
    )
    choice(
      name: 'DEPLOY_TIER',
      choices: ['staging', 'production'],
      description: 'Chỉ là lựa chọn policy; không cấp quyền deploy.'
    )
  }

  environment {
    APP_NAME = 'inventory-api'
    LOG_LEVEL = 'info'
  }

  stages {
    stage('Validate và tính runtime metadata') {
      agent { label 'linux' }
      steps {
        script {
          if (params.RELEASE_NOTE.length() > 120) {
            error('RELEASE_NOTE must be 120 characters or fewer')
          }

          def tiers = [
            'staging': 'STAGING',
            'production': 'PRODUCTION',
          ]
          def selectedTier = tiers[params.DEPLOY_TIER]
          if (selectedTier == null) {
            error('DEPLOY_TIER is not allowlisted')
          }

          def mode = params.DRY_RUN ? 'dry-run' : 'preview'
          env.RUN_SUMMARY = "${selectedTier}-${mode}-${env.BUILD_NUMBER}"
        }

        sh '''
          set -eu
          test -n "$RUN_SUMMARY"
          printf '%s\n' "app=$APP_NAME summary=$RUN_SUMMARY level=$LOG_LEVEL"
        '''
      }
    }

    stage('Package preview') {
      agent { label 'linux' }
      environment {
        LOG_LEVEL = 'debug'
      }
      steps {
        withEnv(['LOG_LEVEL=trace']) {
          sh '''
            set -eu
            printf '%s\n' "package app=$APP_NAME summary=$RUN_SUMMARY level=$LOG_LEVEL"
          '''
        }
        sh 'test "$LOG_LEVEL" = "debug"'
      }
    }

    stage('Staging preview') {
      when {
        beforeAgent true
        expression { params.DEPLOY_TIER == 'staging' }
      }
      agent { label 'linux' }
      steps {
        sh '''
          set -eu
          printf '%s\n' "staging preview only: $RUN_SUMMARY"
        '''
      }
    }
  }

  post {
    always {
      echo 'Pipeline finished; no deployment or credential binding was attempted.'
    }
  }
}

Vì sao mẫu không nội suy parameter vào shell

  • RELEASE_NOTE chỉ được kiểm tra độ dài và không bị in. Nó có thể chứa nội dung tự do, nên không xuất hiện trong shell, path, URL, hostname hay message có khả năng bị diễn giải.
  • DEPLOY_TIER có choice và còn được map lại qua tiers. Shell chỉ nhận RUN_SUMMARY được tạo từ map cố định, boolean và build number.
  • DRY_RUN đi qua biểu thức boolean để tạo dry-run hoặc preview; không phải một chuỗi do user truyền vào command.
  • Stage Staging preview chỉ quyết định có in một dòng cố định hay không. Dù chọn production, mẫu không deploy và không mở endpoint nào.

Trong Pipeline thật, target phải được map trong code/cấu hình đáng tin cậy sang endpoint cố định, còn authorization tồn tại ở Jenkins và hệ thống đích. Thêm gate/approval phù hợp theo Điều kiện when và phê duyệt input, không biến parameter thành lối tắt qua các gate đó.

Credential, secret và ranh giới tin cậy

Binding ở scope hẹp

Không truyền secret bằng string parameter hay environment hard-code. Tạo credential trong Jenkins, cấp scope folder/job hẹp nhất rồi bind đúng block cần dùng. credentials('credential-id') là helper của Declarative environment; withCredentials là step của plugin Credentials Binding. Chúng là capability khác với params và cần credential ID tồn tại cùng permission phù hợp.

withCredentials([
  string(credentialsId: 'release-api-token', variable: 'API_TOKEN')
]) {
  sh '''
    set +x
    # Công cụ đã review đọc API_TOKEN từ environment.
    ./scripts/publish-release
  '''
}

Đây chỉ là pattern tham chiếu, không phải một phần của lab/mẫu chạy được ở trên. Nó giả định plugin Credentials Binding và script ./scripts/publish-release tồn tại; kiểm tra snippet, version plugin và quyền trên controller của bạn. Giữ binding ngắn, dùng single quote/triple single quote để tránh Groovy interpolation của secret, và không gửi token qua URL hoặc command line.

Masking không thay thế bảo mật

Jenkins/Credentials Binding cố gắng mask secret đã biết trong Console Output, kể cả một số dạng shell-escaped. Masking không chặn code có secret gửi nó ra network, ghi vào file/artifact/cache, biến đổi/encode nó hoặc để process khác cùng agent đọc. Không echo, printenv, env, set, cat hay bật set -x quanh binding.

Nếu secret đã xuất hiện trong log

Đừng coi các dấu **** là bằng chứng không có lộ lọt. Dừng dùng credential theo incident process, rotate hoặc thu hồi giá trị ở hệ thống cấp secret, đánh giá log/artifact/report liên quan và sửa Pipeline. Xóa một dòng log không thu hồi bản sao đã bị đọc.

Xem hướng dẫn đầy đủ, gồm secret file và workspace, ở Credentials trong Pipeline.

PR, fork và plugin assumptions

Jenkinsfile, dependency, source và parameter từ pull request (PR), đặc biệt PR từ fork, đều là input không tin cậy. Không cấp credential phát hành, Docker socket, cloud role, agent chứa dữ liệu nhạy cảm hoặc quyền production cho build đó. Chạy CI không tin cậy trên agent tách biệt; chỉ bind capability nhạy cảm sau merge hoặc trong flow được tổ chức tin cậy/phê duyệt.

environment, parameters, when và cấu trúc pipeline {} cần plugin Pipeline: Declarative. withEnv, sh, withCredentials, Branch Source metadata và integration deploy có thể do plugin/OS khác cung cấp, với behavior/version khác nhau. Pipeline Syntax và Declarative linter của controller là nguồn xác nhận cho instance đang chạy; tài liệu cú pháp chung không chứng minh agent có tool, credential có permission hay plugin đã cài. Để chuẩn bị controller/agent lab, xem Yêu cầu hệ thống và chạy Jenkins với Docker.

Lab: quan sát scope và dynamic value

Chuẩn bị

Lab dùng Jenkinsfile mẫu ở trên và không cần repository ứng dụng, credential hay service ngoài. Cần Jenkins có Pipeline: Declarative, agent Unix online có label linux, shell sh và quyền tạo Pipeline job. Nếu agent không có label đó, sửa label của lab thành label thực tế; không dùng controller/built-in node cho workload không tin cậy.

Tạo Jenkinsfile lab

Tạo repository Git do bạn kiểm soát, thêm mẫu vào file Jenkinsfile, commit rồi push. Trong Jenkins tạo New Item → Pipeline, chọn Pipeline script from SCM, chọn Git và branch lab. Nếu repository private, dùng credential đọc source có quyền tối thiểu; không dán token vào URL.

Xác minh cú pháp và parameter

Mở Pipeline Syntax hoặc Declarative Directive Generator để đối chiếu directive theo plugin của controller. Nếu controller cho phép, chạy Declarative linter trước build. Chạy build đầu tiên với default để Jenkins lưu parameter properties; sau đó mở Build with Parameters và xác nhận ba control RELEASE_NOTE, DRY_RUN, DEPLOY_TIER xuất hiện.

Chạy staging và đọc log

Chọn DEPLOY_TIER=staging, DRY_RUN=true, đặt RELEASE_NOTE thành một câu ngắn không nhạy cảm, rồi chạy build. Không đặt hostname, URL, shell fragment hay secret vào note: mẫu cố ý không dùng note trong command.

Kiểm tra scope ngắn hạn

Trong Console Output, so sánh dòng đầu tiên từ Validate và tính runtime metadata với dòng từ Package preview. Dòng package phải có level=trace trong withEnv; test sau block phải thành công vì LOG_LEVEL đã quay lại debug. Stage Staging preview chạy và chỉ in preview cục bộ.

Chạy các trường hợp

Thao tácKết quả mong đợiĐiều được chứng minh
Default: staging, DRY_RUN=trueRUN_SUMMARY có dạng STAGING-dry-run-<build>; cả ba stage chạy.Dynamic value chỉ gồm allowlist, boolean và build number.
Đổi DRY_RUN=falseSummary đổi thành STAGING-preview-<build>; không có side effect mới.Boolean được resolve trong script, không phải chuỗi shell.
Đổi DEPLOY_TIER=productionStaging preview bị skipped; hai stage trước vẫn chạy, không deploy.Choice điều khiển when, không cấp authorization.
Nhập note dài hơn 120 ký tựBuild thất bại ở Validate và tính runtime metadata; note không được echo.String parameter được validate trước khi dùng và không đi vào shell.

Sau mỗi build, đọc build number, stage state và Console Output thay vì chỉ nhìn trạng thái xanh/đỏ. Nếu build chờ queue, kiểm tra agent linux và executor trước khi sửa Jenkinsfile. Để hiểu job, build, agent và log, xem Tổng quan Jenkins Pipeline và Jenkinsfile.

Lỗi thường gặp

Dùng parameter như một mảnh command

sh "curl https://${params.HOST}/deploy", sh params.COMMAND hoặc ghép params vào path/URL là injection/SSRF risk, kể cả khi UI có choice. Map lựa chọn allowlist sang giá trị cố định trong code đáng tin cậy; từ chối giá trị lạ trước mọi network hoặc side effect.

Triệu chứngNguyên nhân thường gặpCách sửa an toàn
$APP_NAME rỗng hoặc literal trong logNhầm params với env, hoặc dùng quote/Groovy interpolation không đúng.Dùng params.NAME trong Groovy; dùng $NAME trong script single-quoted để shell mở rộng environment.
Stage không thấy giá trị pipeline-level mong đợiStage-level environment hoặc withEnv đã che cùng tên biến.Đọc bảng scope, đổi tên biến theo trách nhiệm và thu hẹp withEnv.
env.NAME = không đổi hằng DeclarativeBiến đã được khai báo bằng environment.Giữ hằng đó bất biến; dùng withEnv cho override tạm hoặc đặt biến runtime tên mới.
when vẫn chiếm executor rồi mới skipwhen được đánh giá theo thứ tự mặc định.Thêm beforeAgent true khi condition chỉ đọc parameter/metadata.
Parameter chưa hiện trong UIJob chưa chạy Jenkinsfile để lưu properties, hoặc job đang đọc revision khác.Chạy build lab đầu tiên, xác minh branch/Script Path rồi mở lại Build with Parameters.
Secret bị mask nhưng vẫn có rủi roMasking chỉ che log, không cô lập process, file hay network.Thu hẹp binding, tắt tracing, không archive/dump environment và tách agent PR.
Step hoạt động ở Jenkins khác nhưng không ở đâyThiếu plugin, khác version hoặc agent OS/toolchain khác.Dùng Pipeline Syntax/linter của controller và kiểm tra plugin/agent assumptions.

Checklist

  • environment chỉ chứa cấu hình không nhạy cảm hoặc credential reference đã review; không hard-code secret.
  • Tôi đọc đúng env.NAME và params.NAME như hai namespace riêng.
  • Pipeline-level, stage-level và withEnv có scope tối thiểu; tên biến không che nhau vô tình.
  • Override tạm dùng withEnv; hằng Declarative không bị sửa bằng env.NAME =.
  • Parameter string có giới hạn/validation và không xuất hiện trong shell, URL, hostname, path, artifact hay log.
  • Choice/boolean được map hoặc so sánh rõ ràng trước flow có tác động; parameter không được coi là authorization.
  • Dynamic value được tính sau khi có runtime context, validate trước khi dùng và không thực thi command do input cung cấp.
  • Shell dùng single quote/triple single quote khi cần shell mở rộng biến; không Groovy-interpolate secret.
  • Credential binding ở closure/stage hẹp nhất; không echo, set -x, dump environment hoặc archive dữ liệu binding.
  • PR/fork không nhận secret hay agent đặc quyền; plugin, step, agent và credential assumptions đã được xác minh trên controller.
  • Lab đã chứng minh ít nhất một override withEnv, một dynamic value, một stage when chạy và một stage bị skip.

Nguồn Jenkins chính thức

Đọc tiếp

On this page