iT邦幫忙

2026 iThome 鐵人賽

DAY 23
0
Kubernetes

防範軟體供應鏈攻擊:從零打造具備硬性阻擋能力的雲原生 CI/CD 流水線系列 第 23

Day 23:typecheck、generate-sbom、upload-sbom、cleanup-workspace

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20260823/20183337PFgAtefUlA.png
一口氣多了不少TASK(汗)

環境:單節點 CRC 4.21.14 / Nx 23.1.1 / TypeScript 6.0.3 / Angular 22 / 只有 apps/web 一個專案。

這四個 Task 各做什麼

Task 做的事 為什麼要有
typecheck tsconfig.app.jsontsconfig.spec.json 各跑一次 tsc --noEmit 測試檔的型別沒有任何關卡在看。 build 不編 spec、jest 走 transpile、lint 不管型別
generate-sbom cyclonedx-npmpackage-lock.json,產出一份 CycloneDX JSON 記下這次建構到底裝了哪 1257 個套件。將來某個套件爆 CVE 時要靠它盤點
upload-sbom 把那份 JSON PUT 到 Nexus 的 sbom-raw repo 留在 workspace 裡的檔案下一輪就被刪了。沒存出去的 SBOM 等於沒產出
cleanup-workspace 刪掉共用 PVC 上的 node_modules / .nx / .angular / dist / coverage 這個不在原本計畫裡,是被逼出來的(第五節)

新Task概述

原本的 npm-build 拆成 npm-install + nx-buildtypecheck 插在中間。DAG 從 8 個 Task 變成 12 個 + 1 個 finally。

新 Task 掛在哪 耗時 選這個位置的理由
typecheck npm-install 之後、nx-build 之前 11s 先擋型別錯,nx-build 就不必為注定失敗的程式碼跑一次
generate-sbom git-clone 之後 18s 不需要 node_modules,跟四個掃描並行
upload-sbom generate-sbom 之後 7s 緊接產出
cleanup-workspace finally 11s 前面紅燈時也要跑

critical path 固定變長 11 秒。換到的是:型別錯的那次,nx-build 完全不用起跑。 這台觀測到 nx build 落在 21~488 秒之間。(註:直接把CRC記憶體調高nx-build就沒事了,記憶體不足的情況下npm install 會讓系統部分功能被砍掉)


一、DAG

git-clone ──┬─► workspace-probe ─┐
            ├─► gitleaks-scan ───┤
            ├─► semgrep-scan ────┤
            ├─► sca-scan ────────┼─► npm-install ─► typecheck ─► nx-build ─┬─► eslint-check
            │                    │                                         └─► unit-test
            └─► generate-sbom ───┘
                    │
                    └────────────────────────────────────────────────► upload-sbom

finally: cleanup-workspace

一次實跑的完整耗時

git-clone          10s
gitleaks-scan       7s  ─┐
sca-scan           12s   │
semgrep-scan       16s   ├ 並行
generate-sbom      18s   │
workspace-probe    48s  ─┘
upload-sbom         7s
npm-install        38s
typecheck          11s   ← 卡在 critical path
nx-build          488s
eslint-check       85s  ─┐ 並行
unit-test          89s  ─┘
cleanup-workspace  11s   (finally)
整條            11m41s

nx-build 一個人佔掉七成。三個新 Task(typecheck + generate-sbom + upload-sbom)加起來 36 秒,cleanup-workspace 再 11 秒。

為什麼這樣排

前提是這台的資源狀況:

memory requests  10181Mi / 11781652Ki  (88%)

餘裕約 1.5 GiB。跑一顆量測 Pod 就會讓 API server 出現 TLS handshake timeout,寫這篇的過程中發生了六次以上。

工作 耗時 峰值 RSS
typecheck 4s(tsc 本身) 213 MB
generate-sbom 4~5s 213 MB
unit-test 7~21s 1441~1722 MB
nx build 21~488s 2025 MB
Node 預設 heap 上限 2096 MB

四個決定:

typecheck 放在 nx-build 前面。 這需要把原本的 npm-buildnpm ci + nx build 兩件事塞在一個 step)拆成 npm-installnx-build。拆完 npm-install 是 38 秒,跟拆之前的 npm ci 基準(31~32s)差不多,沒有付出額外的安裝成本。

typecheck 不當成 nx-build 的 step。 nx build 峰值 2025 MB 頂在 2096 MB 的上限上。Kubernetes 算 Pod 的 requests/limits 是把所有 container 加總的,不管 Tekton 其實是循序執行 step——多塞一個 step 進去就是把整顆 pod 的預算撐大。拆成獨立 Task,兩邊各自 213 MB。

generate-sbom 不排在 npm-install 後面。 它只讀 package-lock.json,實測在沒有 node_modules 的乾淨 clone 上一樣產出 1257 components。掛在 git-clone 後跟四個掃描並行,那段本來就在等最慢的掃描。

三個新 Task 都不設 memory request。 requests 已經 88%,設了排不進去會直接 Pending。不設反而是它跑得動的原因。

重排的代價

之前(typecheck 並行) 之後(typecheck 串接)
固定成本 0 +11 秒(含 pod 啟動,不只 tsc 的 4 秒)
型別錯時省下 0 整段 nx-build21~488 秒
型別錯時看得到什麼 四道關卡的結果都有 只有型別這一個nx-buildeslint-checkunit-test 全被跳過

最後一列是真的損失。看第六節那次紅燈:同一份 log 裡看得到 unit-test 是綠的(4 passed)、nx-build 也過了,只有 typecheck 紅。「測試全過但型別是壞的」這個對照,是靠並行才看得到的。改成串接之後,那次 run 只會顯示 typecheck 紅、後面 skipped。

拿診斷資訊換速度。nx build 要跑 4~8 分鐘的機器上,這個交換划算。要是你的 build 只有 30 秒,就不划算,維持並行比較好。


二、typecheck

2.1 它抓得到什麼、抓不到什麼

同一個型別錯誤放在不同位置,五道檢查各自的反應(修好 tsconfig.spec.json 之後量的):

錯誤在哪 app.json spec.json nx build nx test nx lint
app.ts(被 spec import) 抓到 抓到 抓到 漏掉 漏掉
app.routes.ts(沒被 spec import) 抓到 漏掉 抓到
孤兒檔(沒人 import) 抓到 漏掉 抓到
*.spec.ts 漏掉 抓到 漏掉 漏掉 漏掉

孤兒檔在這台抓得到,因為 tsconfig.app.json 的 include 是 glob:

"include": ["src/**/*.ts"]

不靠 import 鏈,src 底下所有 .ts 都納入。所以「沒被引用的死碼會漏掉」這個常見說法,在這種寫法下不成立。

2.1.1 兩個 tsconfig 的分工

看第 1~3 列:app.json 抓得到的,nx build 全都抓得到。 涵蓋範圍上那半是重複的。

但重複不等於沒用——重排之後,app.json 那半的價值從「多防一點」變成「早一點」:app.ts 的型別錯在第 11 秒被攔下,nx-build 那 488 秒完全不用起跑。附帶好處是錯誤訊息乾淨很多,typecheck 的 log 只有 252 bytes,npm-install 的有 5683 bytes(npm ci 的輸出混在裡面)。

看第 4 列:spec 檔的型別,五道裡只有 spec.json 看得見。 tsconfig.app.json 明確 exclude 掉 *.spec.tsnx build 走的也是 app 這條線,jest-preset-angular 走 transpile 不做完整型別檢查。

spec.json 實際編 6 個檔案,其中只有 3 個是別人不看的:

檔案 怎麼進來的 別人有在看嗎
src/test-setup.ts files 沒有
src/app/app.spec.ts include 沒有
src/app/format-utils.spec.ts include 沒有
src/app/app.ts 被 spec import nx build 也看
src/app/nx-welcome.ts 被 spec import nx build 也看
src/app/format-utils.ts 被 spec import nx build 也看

那 3 個檔案就是這道關卡唯一獨佔的守備範圍。聽起來很少,但測試檔正是 mock 和 fixture 住的地方——一份沒被型別檢查的測試,驗的是你手寫的那個形狀,不是產品程式碼真正的形狀。

順帶一提,spec.jsoninclude 裡有一項 "jest.config.ts" 是死的——這個 repo 的檔名是 jest.config.cts,一個檔案都沒 match 到。

2.2 Task

steps:
  - name: typecheck
    image: nexus-nexus-proxy.apps-crc.testing/docker-proxy/library/node:22-alpine
    workingDir: $(workspaces.source.path)
    script: |
      #!/bin/sh
      set -e
      test -d node_modules || { echo "沒有 node_modules,npm-install 沒跑過"; exit 1; }

      TSC=node_modules/.bin/tsc
      echo "tsc $($TSC --version)"

      FAILED=0
      for TSCONFIG in \
        $(params.APP_DIR)/tsconfig.app.json \
        $(params.APP_DIR)/tsconfig.spec.json; do
        echo "--- $TSCONFIG"
        if $TSC --noEmit -p "$TSCONFIG"; then echo "OK"; else echo "FAILED"; FAILED=1; fi
      done

      [ $FAILED -eq 0 ] || { echo "TypeScript type check failed"; exit 1; }
      echo "All type checks passed"

三個細節:

  • node_modules/.bin/tsc 精確路徑。 alpine 容器裡 tsc 不在 $PATHnpx tsc 的解析行為也不保證一致。
  • FAILED=1 累積。 兩個 tsconfig 跑完再統一失敗,一次看到全貌。
  • ⚠️ 不要放 tsconfig.json
apps/web/tsconfig.json        →  檢查了 0 個檔案
apps/web/tsconfig.app.json    →  10 個
apps/web/tsconfig.spec.json   →  6 個

tsconfig.json 是 solution-style(files: []include: []、只有 references)。tsc --noEmit -p 它會 exit 0,但什麼都沒檢查。跟 Day 22 那幾個陷阱同一族。


三、開關卡照出來的第一件事

typecheck 寫好,還沒接進 DAG 就先在本機跑了一次:

apps/web/tsconfig.spec.json(11,25): error TS5107: Option 'moduleResolution=node10' is
  deprecated and will stop functioning in TypeScript 7.0.

照它建議加 "ignoreDeprecations": "6.0",換成兩個新錯:

app.spec.ts(1,25): error TS2307: Cannot find module '@angular/core/testing'
test-setup.ts(4,3): error TS2353: 'errorOnUnknownElements' does not exist in type 'SetupOptions'

第二個很容易讓人以為 Angular 22 拿掉了那個 API。翻 .d.ts

node_modules/@angular/core/types/testing.d.ts:330:  errorOnUnknownElements?: boolean;

它好好的在那裡。TS2353node10 解析不到正確 .d.ts 的症狀,跟 TS2307 同一個根因。

實測六種改法,只有兩種過:moduleResolution: "bundler",或整行拿掉繼承 tsconfig.base.json(它本來就是 bundler)。node16 / nodenext 還要一起改 module

  // apps/web/tsconfig.spec.json
-   "moduleResolution": "node10"
+   "moduleResolution": "bundler"

改完 nx test / nx build / nx lint 都不受影響。

這個設定檔從專案建立那天起就沒被任何關卡碰過。 build 不看 spec 這條線、jest 走 transpile、lint 不管型別。所以它壞了多久沒人知道。

導入新關卡要把這段時間算進預算,寫完 YAML 不是結束。


四、generate-sbom + upload-sbom

4.1 位置

--package-lock-only 只讀 package-lock.json。實測:

有 node_modules:    1257 components,3 秒
沒有 node_modules:  1257 components,4 秒

一樣。所以掛在 git-clone 後面,跟掃描並行,對 critical path 的貢獻是 0。

4.2 三處跟常見寫法不同

① 鎖版本

npm install -g "@cyclonedx/cyclonedx-npm@$(params.CYCLONEDX_VERSION)" --prefer-offline --quiet

不鎖的話同一份 YAML 在不同時間裝到不同版本。SBOM 的產生器版本本身就是供應鏈資訊。

② 用 Tekton result 傳檔名

常見寫法是兩個 Task 各拼一次 sbom-$(git-revision).json。改了一邊沒改另一邊,Tekton 不會報錯,只會在執行期走進「檔案不存在」那條分支。

  results:
    - name: sbom-file
    - name: component-count
  - name: upload-sbom
    params:
      - name: SBOM_FILE
        value: $(tasks.generate-sbom.results.sbom-file)

實跑的 result:

  component-count   "1257"
  sbom-file         sbom-7d9158a.json

component 數順便當 result,PipelineRun 上直接看得到。

③ 找不到檔案 exit 1,不是 exit 0

常見寫法是警告後放行。那條分支的語意不對稱:

情況 行為 Pipeline
找不到 SBOM exit 0 全綠
上傳失敗 exit 1 擋下

SBOM 缺一份、Pipeline 全綠,要等到真的要盤點某個 CVE 影響範圍時才會發現那次建構的成分表從來沒存在過。

4.3 --ignore-npm-errors

很多教學說這個旗標是必要的,因為 cyclonedx-npm 內部的 npm ls 會因套件版本衝突中斷(exit 254)。

這台沒有那個問題:

$ npm ls --json --long --all --package-lock-only
exit=0,stderr 空的

留著是為了將來 npm ls 一有抱怨時不要整個 Task 掛掉。註解要寫實話,不要假裝踩過沒踩過的坑。

4.4 Nexus 端

原本只有 Day 20 建的 semgrep-rules。不要沿用,保存語意相反:

Semgrep 規則快照 每天被覆蓋成最新版
SBOM 每次建構各留一份,只增不減

照 Day 20 的形態另開一組,權限只涵蓋 sbom-raw

repo   sbom-raw               raw hosted
role   sbom-raw-writer        browse / read / add / edit
user   sbom-writer
secret sbom-writer-credentials(ci namespace)

上傳用 node:22-alpine 的內建 fetch,不另外拉 curl 映像。那個映像全線都在用、已經在節點上了。


五、cleanup-workspace

這個不在原本的計畫裡,是被逼出來的。

本節的數字量於拆 Task 之前,那時 npm cinx build 還合在一個叫 npm-build 的 Task 裡。
對應到現在就是 npm-install + nx-build 兩個加起來。

5.1 起因

有一次 webhook 觸發的 run 掛了,REASONPipelineRunTimeoutunit-testTaskRunCancelled

我第一眼的判斷是「git-clone 花了 9m46s」——那是錯的oc get taskrunSTARTTIMECOMPLETIONTIME 兩欄都是「距今多久」,要相減才是耗時。

用時間戳重算:

  npm-build         455s   Succeeded        ← 真正吃掉時間的
  unit-test          71s   TaskRunCancelled
  eslint-check       70s   TaskRunCancelled
  git-clone          25s   Succeeded        ← 一點都不慢

npm-build 一個人吃掉 455 秒,10 分鐘的 timeouts.pipeline 見底,後面兩個被連坐取消。

TaskRunCancelled 不代表那道關卡擋了東西,代表它根本沒跑完。
StepFailed 才是真的失敗。

5.2 共用 PVC 累積了什麼

785 MB / 53067 個檔案(node_modules 佔 774.9 MB)

git-clone 的清理邏輯(從 Task 的 base64 解出來):

clean_dir() {
    rm -rfv ${_dir:?}/*
    rm -rfv ${_dir}/.[!.]*
    rm -rfv ${_dir}/..?*
}
...
clean_dir ${checkout_dir} || true

-v 把刪掉的每個 path 印一行。實測 git-clone 的 pod log 5.2 MB / 60594 行(對照:npm-build 的 log 只有 5.7 KB)。

|| true 把清理失敗吞掉,腳本繼續走到 git-init,然後噴出 cannot copy ... pre-push.sample: File exists。看起來像 git 壞了,實際是上一步沒清乾淨。

5.3 Task

finally:
- name: cleanup-workspace
  taskRef:
    kind: Task
    name: cleanup-workspace
  workspaces:
  - name: source
    workspace: shared-workspace
#!/bin/sh
# 刻意不用 set -e:清理失敗不該把整條 pipeline 變紅
echo "=== 清理前 ==="
du -sh . ; echo "檔案數 = $(find . -type f | wc -l)"

for D in node_modules .nx .angular dist coverage; do
  [ -e "$D" ] || continue
  SIZE=$(du -sh "$D" | cut -f1)
  rm -rf "$D" && echo "已刪除 $D($SIZE)" || echo "刪除 $D 失敗"
done

echo "=== 清理後 ==="
du -sh . ; echo "檔案數 = $(find . -type f | wc -l)"
exit 0

finally 不放 tasks runAfter 在前面紅燈時不會跑,而 workspace 最需要被清的時候正好就是失敗那次(5.1 那次就是這樣留下 787 MB 的)。

不用 rm -rfv -v 正是 git-clone 那 5.2 MB log 的來源。這裡只印摘要。

⚠️ 舊版 Tekton 有個 bug:pipeline timeout 時 finally 會被直接跳過,v1.13.0 才修成 PipelineRunTimeoutRunningFinally
5.1 那次正好就是 timeout。我沒有查 CRC 4.21.14 帶的 OpenShift Pipelines 是哪一版,你自己的環境值得確認一次。

5.4 效果

同一顆共用 PVC 連跑兩輪(run A 開始時是髒的,run B 開始時是乾淨的):

run A run B
git-clone 的 pod log 5448035 bytes 6705 bytes
刪掉的 path 數 60594 89
git-clone 耗時 25s 9s
npm-build 耗時 365s 229s
整條 8m05s 5m40s

cleanup-workspace 的 log:

=== 清理前 ===
787.5M  .
檔案數 = 53068
已刪除 node_modules(774.9M)
已刪除 .nx(4.4M)
已刪除 .angular(1.9M)
已刪除 dist(2.2M)
=== 清理後 ===
4.1M    .
檔案數 = 68

這裡沒有多花的成本。 git-cloneDELETE_EXISTING 預設就是 true,本來每次就會把 node_modules 刪光,npm ci 本來就每次重裝。這只是把刪除從「下一輪的開頭」搬到「這一輪的結尾」。

5.5 有多相信這組數字

git-clone 那兩欄是確定的:60594 → 89 個 path 不受叢集負載影響。

npm-build 的 365s → 229s 只有各一次樣本。這台的 npm-build 本來就在 253~455s 之間跳,229s 雖然低於先前所有觀測值,但單一樣本不足以宣稱 −37%。方向對,倍數不對。

229s 也仍然遠高於全新 volumeClaimTemplate PVC 的 61s。清理有幫助,沒有把差距補平。


六、實跑

6.1 綠燈

$ oc get taskrun -n ci -l tekton.dev/pipelineRun=d23-order
git-clone / workspace-probe / gitleaks-scan / semgrep-scan / sca-scan
generate-sbom / upload-sbom / npm-install / typecheck / nx-build / eslint-check / unit-test
+ finally: cleanup-workspace
→ 全部 Succeeded,逐項耗時見第一節
上傳 sbom-7d9158a.json → .../repository/sbom-raw/web/sbom-7d9158a.json
HTTP 201

Nexus 上:/web/sbom-7d9158a.json 2752214 bytes

6.2 紅燈

在 spec 檔放一個執行期完全正常、只有型別錯的測試:

it('型別錯誤,但測試會過', () => {
  const result: number = formatDisplayName('ada');   // 回傳 string
  expect(result).toBe('ADA');
});

push 之後 webhook 自動觸發:

Tasks Completed: 11 (Failed: 1, Cancelled 0), Skipped: 0

npm-build       True    Succeeded
eslint-check    True    Succeeded
unit-test       True    Succeeded
typecheck       False   StepFailed     ← 只有它

這次紅燈量於重排之前,所以四道關卡的結果都看得到。
改成 typecheck → nx-build 串接之後,同樣的錯誤只會顯示 typecheck 紅、
nx-build / eslint-check / unit-test 全部 skipped——這就是第一節「重排的代價」那一列講的損失。

typecheck

--- apps/web/tsconfig.app.json
OK
--- apps/web/tsconfig.spec.json
format-utils.spec.ts(18,11): error TS2322: Type 'string' is not assignable to type 'number'.
FAILED

同一次 run 的 unit-test

Test Suites: 2 passed, 2 total
Tests:       4 passed, 4 total
NX   Successfully ran target test for project web

測試全過、build 過、lint 過,型別是壞的。 四道關卡只有一道看得到。

Day 22 是「測試全過,但覆蓋率退步」。這篇是它的鏡像。


七、環境備註

現象 說明
oc 頻繁 TLS handshake timeout requests 88% / 92 個 running pod。nx-build 一跑起來 API server 就抖。建立物件要寫重試
MutatingAdmissionWebhook failed to complete mutation in 13s 同一個成因,oc create 重試一次通常就過
讀 TaskRun 耗時 STARTTIME / COMPLETIONTIME 兩欄都是「距今多久」。要用 .status.startTime / .status.completionTime 相減
測試時不要輪詢 每 20 秒一次 oc get 會讓已經吃緊的 API server 更糟。用 oc wait --for=jsonpath='{.status.completionTime}',單一 watch

收工清單

編排

  • [ ] generate-sbomgit-clone 後,不是 npm-install
  • [ ] typecheck 夾在 npm-installnx-build 中間,是獨立 Task 不是 step
  • [ ] cleanup-workspacefinally,不是 runAfter
  • [ ] 確認 Tekton 版本夠新,finally 在 timeout 時會跑
  • [ ] 新 Task 不設 memory request(這台 requests 88%)

typecheck

  • [ ] node_modules/.bin/tsc 精確路徑
  • [ ] FAILED=1 累積
  • [ ] 不要放 solution-style 的 tsconfig.json
  • [ ] 先跑一次看現有設定檔過不過,大概率不過

SBOM

  • [ ] -f-s 都檢查
  • [ ] cyclonedx-npm 鎖版本
  • [ ] 用 result 傳檔名
  • [ ] 找不到檔案 exit 1
  • [ ] 獨立的 raw repo,權限只給那一個

cleanup

  • [ ] 不用 rm -rfv
  • [ ] 不用 set -e,清理失敗不該讓 pipeline 變紅
  • [ ] 但也不要 || true 靜靜吞掉,要把結果印出來

收尾

四個新 Task 加起來 47 秒,但真正動到 critical path 的只有 typecheck 那 11 秒——generate-sbomupload-sbom 躲在掃描的並行段裡,cleanup-workspacefinally

那 11 秒是刻意付的。 換到的是型別錯的那次 nx-build 不用起跑,代價是那次 run 只看得到型別這一項。build 慢的機器划算,build 快的機器不划算。

真正花掉時間的是兩件計畫外的事:tsconfig.spec.json 從專案建立那天起就沒被檢查過,所以關卡一開就是紅的;共用 PVC 累積的 53067 個檔案讓 git-clone 的 log 膨脹到 5.2 MB。

第一件是導入新關卡的固定成本,寫完 YAML 不是結束。第二件是誤診——我先把帳算在 git-clone 頭上,是因為把 oc get taskrun 的兩個 age 欄位讀成了「開始時間 / 持續時間」。

Day 24 進入映像檔封裝:Rootless Buildah,以及虛擬機環境下儲存驅動的設定限制。


參考文件

Tekton:finally 與逾時(§一、§五)

  • Pipelines — Adding Finally to the Pipeline —— finally 的保證:「guaranteed to be executed in parallel after all PipelineTasks under tasks have completed regardless of success or error」。這就是 cleanup-workspace 放這裡而不是 runAfter 的依據
  • PipelineRuns — Configuring a failure timeout —— 收工清單那條「確認 finally 在 timeout 時會跑」的正解。三個欄位的語意不同:
    • timeouts.pipeline 到期 → 「any running child TaskRuns will be canceled, regardless of whether they are normal Tasks or finally Tasks」,finally 也會被砍
    • timeouts.tasks 到期 → 「finally Tasks will run if timeouts.finally is specified
    • 換句話說,要讓清理在逾時後仍然跑完,得同時timeouts.taskstimeouts.finally,不是只靠版本夠新

Tekton:Results(§4.2 ②)

  • Tasks — Emitting Results —— 用 result 傳檔名而不是兩邊各拼一次的依據。同一頁講了兩個限制:
    • 大小上限 4096 bytes(受 k8s container termination message 限制),而且「the more steps you have in a Task, the smaller the result for each step can be」
    • 官方建議的用途正好是這種:「small amounts of data, such as commit SHAs, branch names, ephemeral namespaces」。超過約 1KB 就該改用 workspace

TypeScript:solution-style tsconfig(§2.2)

  • Project References — Guidance —— §2.2 那個「tsc --noEmit -p tsconfig.json 檢查了 0 個檔案」的出處。文件描述的正是這種寫法:「a "solution" tsconfig.json file that simply has references to all of your leaf-node projects and sets files to an empty array」,而且明講:

    「to preserve compatibility with existing build workflows, tsc will not automatically build dependencies unless invoked with the --build switch」

    所以要嘛用 tsc -b,要嘛像本篇一樣直接指向葉子設定檔(tsconfig.app.json / tsconfig.spec.json)。用 -p 指 solution 檔會 exit 0 而什麼都沒做——不是 bug,是文件寫明的行為

  • tsconfig 參考:files / include / references —— §2.1 那張表為什麼「孤兒檔抓得到」:include 是 glob,不靠 import 鏈

CycloneDX:SBOM 產生(§4.1、§4.2 ①、§4.3)

  • CycloneDX/cyclonedx-node-npm —— 套件是 @cyclonedx/cyclonedx-npm。三個本篇用到的旗標,官方原文:
    • --package-lock-only:「Whether to only use the lock file, ignoring "node_modules"」——§4.1 那個「有沒有 node_modules 都是 1257 components」的原因
    • --ignore-npm-errors:「Whether to ignore errors of NPM. This might be used, if "npm install" was run with --force or --legacy-peer-deps」——⚠️ 注意官方給的理由比「很多教學」講的窄,沒有提到 npm ls exit 254 或版本衝突。§4.3 那段的保留態度是有根據的
    • --spec-version:預設 1.6
  • CycloneDX 規格 —— SBOM 格式本身
  • OWASP CycloneDX 工具中心 —— 其他語言/生態的產生器

Nexus:raw repository(§4.4)

  • Raw Repositories —— 存放路徑格式 /repository/<repo-name>/<file-path>,上傳就是一個 HTTP PUT:
    curl -v --user 'admin:admin123' --upload-file ./test.png \
      http://localhost:8081/repository/documentation/test.png
    
    這就是 upload-sbomnode:22-alpine 內建 fetch 就能做完、不必另外拉 curl 映像的原因

其他

  • kubectl wait —— §七 那條「測試時不要輪詢」:用 oc wait --for=jsonpath='{.status.completionTime}' 開單一 watch,不要每 20 秒 oc get 一次

上一篇
Day 22:把 unit-test 接進 Tekton DAG —— 測試全過,Task 還是紅燈
系列文
防範軟體供應鏈攻擊:從零打造具備硬性阻擋能力的雲原生 CI/CD 流水線23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言