解決 Jenkins 中無法展示 HTML 樣式的問題

問題描述

對於測試報告來說,除了內容的簡潔精鍊,樣式的美觀也很重要。常用的做法是,採用HTML格式的文檔,並搭配CSS和JS,實現自定義的樣式和動畫效果(例如展開、摺疊等)。

在Jenkins中要展示HTML文檔,通常採用的方式有兩種:

  • 使用HTML Publisher Plugin;
  • 使用Files to archive功能,在Build Artifacts中顯示HTML文檔鏈接。

第一種方式配合插件,可以通過圖形化操作實現簡易配置,並且展示效果也不錯;而第二種方式的優勢在於使用Jenkins自帶的功能,不依賴插件也能實現基本的需求。

然而,不管是採用哪種方式,都有可能會遇到一種情況,就是展示出來的HTML報告樣式全無。在瀏覽器的Network中查看資源載入情況,會發現相關的CSS和JS都沒法正常載入。

Refused to load the stylesheet https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css because it violates the following Content Security Policy directive: "style-src self".nRefused to apply inline style because it violates the following Content Security Policy directive: "style-src self". Either the unsafe-inline keyword, a hash (sha256-0EZqoz+oBhx7gF4nvY2bSqoGyy4zLjNF+SDQXGp/ZrY=), or a nonce (nonce-...) is required to enable inline execution.nBlocked script execution in http://10.13.0.146:8888/job/SkyPixel-SmokeTest/34/artifact/reports/SkyPixel-smoketest/34.html because the documents frame is sandboxed and the allow-scripts permission is not set.nRefused to load the stylesheet https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css because it violates the following Content Security Policy directive: "style-src self".n

問題分析

出現該現象的原因在於Jenkins中配置的CSP(Content Security Policy)。

簡單地說,這是Jenkins的一個安全策略,默認會設置為一個非常嚴格的許可權集,以防止Jenkins用戶在workspace、/userContent、archived artifacts中受到惡意HTML/JS文件的攻擊。

默認地,該許可權集會設置為:

sandbox; default-src none; img-src self; style-src self;n

在該配置下,只允許載入:

  • Jenkins伺服器上託管的CSS文件
  • Jenkins伺服器上託管的圖片文件

而如下形式的內容都會被禁止:

  • JavaScript
  • plugins (object/embed)
  • HTML中的內聯樣式表(Inline style sheets),以及引用的外站CSS文件
  • HTML中的內聯圖片(Inline image definitions),以及外站引用的圖片文件
  • frames
  • web fonts
  • XHR/AJAX
  • etc.

可以看出,這個限制非常嚴格,在此限制下也就不難理解為什麼我們的HTML沒法正常展示樣式了。

解決方案

臨時解決方案

要解決該問題,方式也比較簡單,就是修改Content Security Policy的默認配置。

修改方式為,進入Manage Jenkins->Script console,輸入如下命令並進行執行。

System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "")n

當看到如下結果後,則說明配置修改已經生效。

ResultnResult: n

再次進行構建,新生成的HTML就可以正常展示樣式了。需要說明的是,該操作對之前構建生成的HTML報告無效。

永久解決方案

不過,該方法還存在一個問題:該配置只是臨時生效,當重啟Jenkins後,Content Security Policy又會恢復為默認值,從而HTML樣式又沒法展示了。

當前,Jenkins官方還沒有相應的解決方法,我們只能在每次啟動或重啟Jenkins時,重新修改該安全策略。

如果手工地來重複這項工作,也是可行,但並不是一個好的解決方案。

回到剛才的Script console,會發現我們執行的命令其實就是一段Groovy代碼;那麼,如果我們可以實現在Jenkins每次啟動時自動地執行該Groovy代碼,那麼也就同樣能解決我們的問題了。

好在Jenkins已經有相應的插件:

  • Startup Trigger: 可實現在Jenkins節點(master/slave)啟動時觸發構建;
  • Groovy plugin: 可實現直接執行Groovy代碼。

搜索安裝startup-trigger-plugin和Groovy插件後,我們就可以進行配置了。

配置方式如下:

  • 新建一個job,該job專門用於Jenkins啟動時執行的配置命令;
  • 在Build Triggers模塊下,勾選Build when job nodes start;
  • 在Build模塊下,Add build step->Execute system Groovy script,在Groovy Script中輸入配置命令,System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "")。

需要注意的是,添加構建步驟的時候,應該選擇Execute system Groovy script,而不是Execute Groovy script。關於這兩者之間的差異,簡單地說,Groovy Script相當於是運行在master/slave系統JVM環境中,而system groovy script,則是運行在Jenkins master的JVM環境中,與前面提到的Jenkins Script Console功能相同。如需了解更多信息,可查看Groovy plugin的詳細說明。

至此,我們就徹底解決HTML樣式展示異常的問題了。

但還有一點需要格外注意,在本文的演示中,我們修改CSP(Content Security Policy)配置時關閉了的所有安全保護策略,即將hudson.model.DirectoryBrowserSupport.CSP設置為空,其實這是存在很大的安全隱患的。

正確的做法,我們應該是結合項目的實際情況,選擇對應的安全策略。例如,如果我們需要開啟腳本文件載入,但是只限於Jenkins伺服器上託管的CSS文件,那麼就可以採用如下配置。

System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "sandbox; style-src self;")n

除此之外,CSP可以實現非常精細的許可權配置,詳細配置可參考Content Security Policy Reference。

閱讀更多

  • Configuring Content Security Policy
  • Content Security Policy Reference

推薦閱讀:

如何理解持續集成、持續交付、持續部署?

TAG:持续集成CI | HTML | 自动化测试 |