mirror of
https://gitee.com/kekingcn/file-online-preview.git
synced 2026-11-11 13:50:44 +00:00
release: prepare v5.0.3 security fixes and verified deployment
This commit is contained in:
2
.github/scripts/deploy_windows_winrm.py
vendored
2
.github/scripts/deploy_windows_winrm.py
vendored
@@ -40,6 +40,8 @@ def main() -> int:
|
||||
"KK_DEPLOY_MVN_CMD": optional_env("KK_DEPLOY_MVN_CMD", r"C:\kkFileView-tools\maven\bin\mvn.cmd"),
|
||||
"KK_DEPLOY_MAVEN_SETTINGS": optional_env("KK_DEPLOY_MAVEN_SETTINGS", ""),
|
||||
"KK_DEPLOY_DRY_RUN": optional_env("KK_DEPLOY_DRY_RUN", "false").lower(),
|
||||
"KK_DEPLOY_REVISION": optional_env("KK_DEPLOY_REVISION", ""),
|
||||
"KK_DEPLOY_HARDEN_ACTUATOR": optional_env("KK_DEPLOY_HARDEN_ACTUATOR", "false").lower(),
|
||||
}
|
||||
|
||||
script_path = pathlib.Path(__file__).with_name("remote_windows_deploy.ps1")
|
||||
|
||||
127
.github/scripts/remote_windows_deploy.ps1
vendored
127
.github/scripts/remote_windows_deploy.ps1
vendored
@@ -41,6 +41,8 @@ $GitExe = Get-OptionalEnv 'KK_DEPLOY_GIT_EXE' 'C:\kkFileView-tools\git\cmd\git.e
|
||||
$MvnCmd = Get-OptionalEnv 'KK_DEPLOY_MVN_CMD' 'C:\kkFileView-tools\maven\bin\mvn.cmd'
|
||||
$MavenSettings = Get-OptionalEnv 'KK_DEPLOY_MAVEN_SETTINGS' ''
|
||||
$DryRun = Get-OptionalEnv 'KK_DEPLOY_DRY_RUN' 'false'
|
||||
$ExpectedRevision = Get-OptionalEnv 'KK_DEPLOY_REVISION' ''
|
||||
$HardenActuator = (Get-OptionalEnv 'KK_DEPLOY_HARDEN_ACTUATOR' 'false') -eq 'true'
|
||||
|
||||
$BinDir = Join-Path $DeployRoot 'bin'
|
||||
$StartupScript = Join-Path $BinDir 'startup.bat'
|
||||
@@ -202,6 +204,18 @@ function Build-KkFileView {
|
||||
}
|
||||
|
||||
Sync-Repository
|
||||
if (-not [string]::IsNullOrWhiteSpace($ExpectedRevision)) {
|
||||
if ($ExpectedRevision -notmatch '^[0-9a-f]{40}$') {
|
||||
throw 'Deployment revision must be a full commit SHA'
|
||||
}
|
||||
Invoke-External -FilePath $GitExe -Arguments @('fetch', '--depth', '1', 'origin', $ExpectedRevision) -WorkingDirectory $SourceRoot
|
||||
Invoke-External -FilePath $GitExe -Arguments @('checkout', '--detach', $ExpectedRevision) -WorkingDirectory $SourceRoot
|
||||
}
|
||||
$SourceRevision = (& $GitExe -C $SourceRoot rev-parse HEAD).Trim()
|
||||
if ($LASTEXITCODE -ne 0 -or ($ExpectedRevision -and $SourceRevision -ne $ExpectedRevision)) {
|
||||
throw 'Source revision does not match the requested deployment commit'
|
||||
}
|
||||
Write-Step "Building source revision: $SourceRevision"
|
||||
Build-KkFileView
|
||||
|
||||
$DownloadedJars = Get-ChildItem $BuildOutputDir -Filter 'kkFileView-*.jar' -File
|
||||
@@ -295,33 +309,118 @@ function Wait-Health {
|
||||
return $false
|
||||
}
|
||||
|
||||
function Resolve-ActiveConfigPath {
|
||||
param([string[]]$CommandLines, [string]$WorkingDirectory)
|
||||
$Paths = @()
|
||||
foreach ($CommandLine in $CommandLines) {
|
||||
$MatchesFound = [regex]::Matches($CommandLine, '(?:-D|--)spring\.config\.location=(?:"([^"]+)"|([^\s"<>]+))')
|
||||
foreach ($Match in $MatchesFound) {
|
||||
$Value = $Match.Groups[1].Value
|
||||
if (-not $Value) { $Value = $Match.Groups[2].Value }
|
||||
$Value = $Value -replace '^file:', ''
|
||||
if ($Value -match '[,;*?%$]' -or $Value -notmatch '\.properties$') {
|
||||
throw 'Security config migration requires one explicit .properties file'
|
||||
}
|
||||
if (-not [System.IO.Path]::IsPathRooted($Value)) {
|
||||
$Value = Join-Path $WorkingDirectory $Value
|
||||
}
|
||||
$Paths += [System.IO.Path]::GetFullPath($Value)
|
||||
}
|
||||
}
|
||||
$Paths = @($Paths | Select-Object -Unique)
|
||||
if ($Paths.Count -ne 1 -or -not (Test-Path -LiteralPath $Paths[0] -PathType Leaf)) {
|
||||
throw 'Unable to identify a unique active external configuration file'
|
||||
}
|
||||
return $Paths[0]
|
||||
}
|
||||
|
||||
function Set-SecureActuatorDefaults {
|
||||
param([string]$ConfigPath)
|
||||
# Round-trip unrelated bytes unchanged, regardless of the existing encoding.
|
||||
$Encoding = [System.Text.Encoding]::GetEncoding(28591)
|
||||
$Content = $Encoding.GetString([System.IO.File]::ReadAllBytes($ConfigPath))
|
||||
$NewLine = "`n"
|
||||
if ($Content.Contains("`r`n")) { $NewLine = "`r`n" }
|
||||
foreach ($Entry in @(
|
||||
@('management.endpoints.web.exposure.include', 'health'),
|
||||
@('management.endpoint.health.show-details', 'never')
|
||||
)) {
|
||||
$Pattern = '(?m)^[ \t]*' + [regex]::Escape($Entry[0]) + '[ \t]*[=:][^\r\n]*'
|
||||
$Line = $Entry[0] + ' = ' + $Entry[1]
|
||||
if ([regex]::IsMatch($Content, $Pattern)) {
|
||||
$Content = [regex]::Replace($Content, $Pattern, $Line)
|
||||
} else {
|
||||
$Content += $NewLine + $Line + $NewLine
|
||||
}
|
||||
}
|
||||
[System.IO.File]::WriteAllBytes($ConfigPath, $Encoding.GetBytes($Content))
|
||||
}
|
||||
|
||||
function Assert-SecureActuatorExposure {
|
||||
param([string]$Url)
|
||||
$HealthEndpoint = [System.Uri]::new([System.Uri]$Url, 'actuator/health').AbsoluteUri
|
||||
$MetricsEndpoint = [System.Uri]::new([System.Uri]$Url, 'actuator/metrics').AbsoluteUri
|
||||
$Health = Invoke-RestMethod -Uri $HealthEndpoint -TimeoutSec 10
|
||||
if ($Health.status -ne 'UP' -or @($Health.PSObject.Properties).Count -ne 1) {
|
||||
throw 'Health endpoint still exposes component details or is unhealthy'
|
||||
}
|
||||
try {
|
||||
$null = Invoke-WebRequest -Uri $MetricsEndpoint -UseBasicParsing -TimeoutSec 10
|
||||
throw 'Metrics endpoint remains publicly exposed'
|
||||
} catch {
|
||||
if (-not $_.Exception.Response -or [int]$_.Exception.Response.StatusCode -ne 404) {
|
||||
throw
|
||||
}
|
||||
}
|
||||
Write-Step 'Security verification passed: aggregate health only; metrics returns 404'
|
||||
}
|
||||
|
||||
$ActiveConfig = $null
|
||||
$BackupConfig = $null
|
||||
if ($HardenActuator) {
|
||||
$CommandLines = @(Get-KkFileViewJavaProcesses | ForEach-Object { $_.CommandLine })
|
||||
if ($CommandLines.Count -eq 0) { $CommandLines = @(Get-Content -LiteralPath $StartupScript -Raw) }
|
||||
$ActiveConfig = Resolve-ActiveConfigPath -CommandLines $CommandLines -WorkingDirectory $BinDir
|
||||
$BackupConfig = Join-Path $ReleaseDir ("{0}.{1}.bak" -f [System.IO.Path]::GetFileName($ActiveConfig), $Timestamp)
|
||||
Write-Step "Active configuration: $ActiveConfig"
|
||||
Write-Step "Backing up active configuration to $BackupConfig"
|
||||
Copy-Item -LiteralPath $ActiveConfig -Destination $BackupConfig
|
||||
}
|
||||
|
||||
Write-Step "Backing up current jar to $BackupJar"
|
||||
Copy-Item $JarPath $BackupJar -Force
|
||||
|
||||
try {
|
||||
Stop-KkFileView
|
||||
if (-not (Wait-KkFileViewStopped)) {
|
||||
throw "Timed out waiting for the previous kkFileView process to exit"
|
||||
}
|
||||
|
||||
Write-Step "Replacing jar with artifact output"
|
||||
if ($HardenActuator) { Set-SecureActuatorDefaults -ConfigPath $ActiveConfig }
|
||||
Write-Step "Replacing jar with artifact output: $($DownloadedJar.Name)"
|
||||
Copy-Item $DownloadedJar.FullName $JarPath -Force
|
||||
|
||||
Start-KkFileView
|
||||
|
||||
if (-not (Wait-Health -Url $HealthUrl)) {
|
||||
Write-Step "Health check failed, rolling back"
|
||||
throw 'Deployment health check failed'
|
||||
}
|
||||
if ($HardenActuator) { Assert-SecureActuatorExposure -Url $HealthUrl }
|
||||
} catch {
|
||||
$DeploymentError = $_
|
||||
Write-Step 'Deployment verification failed, restoring jar and configuration'
|
||||
Stop-KkFileView
|
||||
if (-not (Wait-KkFileViewStopped)) {
|
||||
throw "Timed out waiting for the failed kkFileView process to exit during rollback"
|
||||
}
|
||||
if (-not (Wait-KkFileViewStopped)) { throw 'Unable to stop the failed deployment for rollback' }
|
||||
Copy-Item $BackupJar $JarPath -Force
|
||||
if ($BackupConfig) { Copy-Item -LiteralPath $BackupConfig -Destination $ActiveConfig -Force }
|
||||
Start-KkFileView
|
||||
|
||||
if (-not (Wait-Health -Url $HealthUrl)) {
|
||||
throw "Deployment failed and rollback health check also failed"
|
||||
}
|
||||
|
||||
throw "Deployment failed, rollback completed successfully"
|
||||
if (-not (Wait-Health -Url $HealthUrl)) { throw 'Deployment and rollback health checks both failed' }
|
||||
throw "Deployment failed; rollback succeeded: $DeploymentError"
|
||||
}
|
||||
|
||||
@{
|
||||
revision = $SourceRevision
|
||||
artifact = $DownloadedJar.Name
|
||||
sha256 = (Get-FileHash -LiteralPath $JarPath -Algorithm SHA256).Hash
|
||||
actuatorHardened = $HardenActuator
|
||||
deployedAt = (Get-Date).ToUniversalTime().ToString('o')
|
||||
} | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $DeployRoot 'deployment.json') -Encoding UTF8
|
||||
Write-Step "Verified deployed revision: $SourceRevision"
|
||||
Write-Step "Deployment completed successfully"
|
||||
|
||||
42
.github/scripts/test_windows_deploy.ps1
vendored
Normal file
42
.github/scripts/test_windows_deploy.ps1
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$Tokens = $null
|
||||
$ParseErrors = $null
|
||||
$ScriptPath = Join-Path $PSScriptRoot 'remote_windows_deploy.ps1'
|
||||
$Ast = [System.Management.Automation.Language.Parser]::ParseFile($ScriptPath, [ref]$Tokens, [ref]$ParseErrors)
|
||||
if ($ParseErrors.Count -gt 0) { throw ($ParseErrors | Out-String) }
|
||||
foreach ($Name in @('Resolve-ActiveConfigPath', 'Set-SecureActuatorDefaults')) {
|
||||
$FunctionAst = $Ast.Find({ param($Node) $Node -is [System.Management.Automation.Language.FunctionDefinitionAst] -and $Node.Name -eq $Name }, $true)
|
||||
if (-not $FunctionAst) { throw "Missing function: $Name" }
|
||||
. ([scriptblock]::Create($FunctionAst.Extent.Text))
|
||||
}
|
||||
|
||||
$TempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ('kkfileview-deploy-test-' + [guid]::NewGuid().ToString('N'))
|
||||
try {
|
||||
$Bin = New-Item -ItemType Directory -Path (Join-Path $TempRoot 'bin')
|
||||
$Config = New-Item -ItemType Directory -Path (Join-Path $TempRoot 'config')
|
||||
$ActiveFile = Join-Path $Config.FullName 'test.properties'
|
||||
$Utf8 = New-Object System.Text.UTF8Encoding($false)
|
||||
$Original = "# Preserve Unicode: 中文`r`ncustom.value = unchanged`r`nmanagement.endpoints.web.exposure.include = health,info,metrics`r`nmanagement.endpoint.health.show-details = always`r`n"
|
||||
[System.IO.File]::WriteAllText($ActiveFile, $Original, $Utf8)
|
||||
$Resolved = Resolve-ActiveConfigPath -CommandLines @('java -Dspring.config.location=..\config\test.properties -jar kkFileView-5.0.jar') -WorkingDirectory $Bin.FullName
|
||||
if ($Resolved -ne $ActiveFile) { throw 'Did not resolve the runtime configuration override' }
|
||||
Set-SecureActuatorDefaults -ConfigPath $Resolved
|
||||
$Expected = $Original.Replace('health,info,metrics', 'health').Replace('show-details = always', 'show-details = never')
|
||||
$Actual = [System.IO.File]::ReadAllText($Resolved, $Utf8)
|
||||
if ($Actual -cne $Expected) { throw 'Migration altered unrelated configuration or missed a security default' }
|
||||
Set-SecureActuatorDefaults -ConfigPath $Resolved
|
||||
if ([System.IO.File]::ReadAllText($Resolved, $Utf8) -cne $Expected) { throw 'Migration is not idempotent' }
|
||||
|
||||
[System.IO.File]::WriteAllText($ActiveFile, 'custom.value = unchanged', $Utf8)
|
||||
Set-SecureActuatorDefaults -ConfigPath $ActiveFile
|
||||
$Actual = [System.IO.File]::ReadAllText($ActiveFile, $Utf8)
|
||||
if ($Actual -notmatch 'management.endpoints.web.exposure.include = health' -or $Actual -notmatch 'management.endpoint.health.show-details = never') {
|
||||
throw 'Missing properties were not added'
|
||||
}
|
||||
$Rejected = $false
|
||||
try { Resolve-ActiveConfigPath -CommandLines @('java -jar app.jar') -WorkingDirectory $Bin.FullName } catch { $Rejected = $true }
|
||||
if (-not $Rejected) { throw 'Unknown active configuration must fail closed' }
|
||||
Write-Host 'Windows deployment syntax and configuration migration tests passed'
|
||||
} finally {
|
||||
if (Test-Path $TempRoot) { Remove-Item -LiteralPath $TempRoot -Recurse -Force }
|
||||
}
|
||||
7
.github/workflows/master-auto-deploy.yml
vendored
7
.github/workflows/master-auto-deploy.yml
vendored
@@ -4,6 +4,11 @@ on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
harden_actuator:
|
||||
description: Apply v5.0.3 monitoring defaults to the active external config
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
concurrency:
|
||||
group: master-auto-deploy-production
|
||||
@@ -29,6 +34,8 @@ jobs:
|
||||
KK_DEPLOY_GIT_EXE: ${{ vars.KK_DEPLOY_GIT_EXE }}
|
||||
KK_DEPLOY_MVN_CMD: ${{ vars.KK_DEPLOY_MVN_CMD }}
|
||||
KK_DEPLOY_MAVEN_SETTINGS: ${{ vars.KK_DEPLOY_MAVEN_SETTINGS }}
|
||||
KK_DEPLOY_REVISION: ${{ github.sha }}
|
||||
KK_DEPLOY_HARDEN_ACTUATOR: ${{ inputs.harden_actuator || 'false' }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
||||
12
.github/workflows/maven.yml
vendored
12
.github/workflows/maven.yml
vendored
@@ -35,6 +35,18 @@ jobs:
|
||||
- name: Build with Maven
|
||||
run: mvn -B package "-Dmaven.test.skip=true" --file pom.xml
|
||||
|
||||
- name: Security regression tests
|
||||
if: runner.os == 'Linux'
|
||||
run: >-
|
||||
mvn -B -pl server
|
||||
-Dtest=FtpCommandSecurityTests,UploadPathSecurityTests,PreviewSourceSecurityTests,PreviewParameterSecurityTests,ArchiveDirectorySecurityTests,ActuatorExposureSecurityTests,ArchiveTraversalSecurityTests,FileControllerPathSecurityTests,FileControllerDeleteSecurityTests
|
||||
test
|
||||
|
||||
- name: Validate Windows deployment
|
||||
if: runner.os == 'Windows'
|
||||
shell: powershell
|
||||
run: .github/scripts/test_windows_deploy.ps1
|
||||
|
||||
- name: Upload Linux distribution package
|
||||
if: success() && runner.os == 'Linux'
|
||||
uses: actions/upload-artifact@v4
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM keking/kkfileview-base:5.0.0
|
||||
ADD server/target/kkFileView-*.tar.gz /opt/
|
||||
ENV KKFILEVIEW_BIN_FOLDER=/opt/kkFileView-5.0.2/bin
|
||||
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dspring.config.location=/opt/kkFileView-5.0.2/config/application.properties","-jar","/opt/kkFileView-5.0.2/bin/kkFileView-5.0.2.jar"]
|
||||
ENV KKFILEVIEW_BIN_FOLDER=/opt/kkFileView-5.0.3/bin
|
||||
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dspring.config.location=/opt/kkFileView-5.0.3/config/application.properties","-jar","/opt/kkFileView-5.0.3/bin/kkFileView-5.0.3.jar"]
|
||||
|
||||
16
README.cn.md
16
README.cn.md
@@ -149,6 +149,22 @@ pdf预览模式预览效果如下
|
||||
|
||||
### 历史更新记录
|
||||
|
||||
#### > 2026年10月08日,v5.0.3 安全补丁版本发布:
|
||||
|
||||
#### 安全修复
|
||||
1. FTP 连接前校验命令参数,阻止控制字符注入
|
||||
2. 上传和建目录限制在演示文件目录内,并检查符号链接
|
||||
3. 校验所有预览源地址,阻止通过不同参数绕过信任策略
|
||||
4. 预览页码和代理参数经过类型校验后再渲染模板
|
||||
5. 在通过校验的压缩包预览中生成目录树,移除公开的 `/directory` 接口
|
||||
6. 默认仅开放汇总健康状态,不再默认暴露健康详情、info 和 metrics
|
||||
|
||||
#### 升级说明
|
||||
1. 建议所有 v5.0.2 及更早版本用户升级至 v5.0.3,继续要求 JDK 21 及以上
|
||||
2. 已有外部配置文件需设置 `management.endpoints.web.exposure.include=health` 和 `management.endpoint.health.show-details=never`,才能应用监控配置加固
|
||||
3. `/directory` 接口已移除,内置压缩包目录预览继续可用
|
||||
4. 上传仍默认禁用;启用后,上传和建目录仅允许演示目录内的路径
|
||||
|
||||
#### > 2026年08月14日,v5.0.2 补丁版本发布 :
|
||||
|
||||
#### 安全修复
|
||||
|
||||
16
README.md
16
README.md
@@ -65,6 +65,22 @@ URL:[https://file.kkview.cn](https://file.kkview.cn)
|
||||
|
||||
## Change History
|
||||
|
||||
### Version 5.0.3 (October 8, 2026)
|
||||
|
||||
#### Security Fixes
|
||||
1. Reject control characters in FTP command arguments before connecting
|
||||
2. Confine uploads and folder creation to demo storage, including symbolic-link checks
|
||||
3. Validate every preview source URL to prevent parameter-confusion bypasses of trust policies
|
||||
4. Validate page and agent parameters before rendering preview templates
|
||||
5. Render archive directory trees within the validated preview flow and remove the public `/directory` endpoint
|
||||
6. Expose only aggregate health status by default; detailed health, info, and metrics are no longer public defaults
|
||||
|
||||
#### Upgrade Notes
|
||||
1. All v5.0.2 and earlier users should upgrade to v5.0.3; JDK 21 or higher remains required
|
||||
2. Existing external configuration files must set `management.endpoints.web.exposure.include=health` and `management.endpoint.health.show-details=never` to apply the monitoring hardening
|
||||
3. The `/directory` endpoint is removed; the built-in archive preview remains supported
|
||||
4. Uploads remain disabled by default. Enabled uploads and folder creation accept only paths beneath demo storage
|
||||
|
||||
### Version 5.0.2 (August 14, 2026)
|
||||
|
||||
#### Security Fixes
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>cn.keking</groupId>
|
||||
<artifactId>kkFileView-parent</artifactId>
|
||||
<version>5.0.2</version>
|
||||
<version>5.0.3</version>
|
||||
|
||||
<properties>
|
||||
<!-- ========== Java 和编译配置 ========== -->
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>kkFileView-parent</artifactId>
|
||||
<groupId>cn.keking</groupId>
|
||||
<version>5.0.2</version>
|
||||
<version>5.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>kkFileView</artifactId>
|
||||
|
||||
@@ -41,10 +41,10 @@
|
||||
你可以先看最新版本的升级重点,再顺着时间轴继续了解历史版本细节。
|
||||
</p>
|
||||
<div class="release-badge-row">
|
||||
<span class="tag highlight">最新版本 v5.0.2</span>
|
||||
<span class="tag brand">发布日期 2026-08-14</span>
|
||||
<span class="tag highlight">最新版本 v5.0.3</span>
|
||||
<span class="tag brand">发布日期 2026-10-08</span>
|
||||
<span class="tag warn">JDK 21+ 强制要求</span>
|
||||
<span class="tag">安全补丁 / HTML、文件删除、PDF 转图修复</span>
|
||||
<span class="tag">安全补丁 / FTP、文件路径、预览与监控加固</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -52,11 +52,39 @@
|
||||
<section class="release-section">
|
||||
<div class="timeline-year">2026</div>
|
||||
<div class="timeline-list">
|
||||
<article class="release-card">
|
||||
<h3>v5.0.3</h3>
|
||||
<div class="release-meta">
|
||||
<span class="tag brand">2026-10-08</span>
|
||||
<span class="tag highlight">最新稳定版本</span>
|
||||
<span class="tag warn">建议尽快升级</span>
|
||||
</div>
|
||||
<div class="release-columns">
|
||||
<div class="release-group">
|
||||
<h4>安全修复</h4>
|
||||
<ul class="release-list">
|
||||
<li>校验 FTP 命令参数,限制上传和建目录路径。</li>
|
||||
<li>校验所有预览源地址,以及页码和代理参数。</li>
|
||||
<li>压缩包目录树改由通过校验的预览生成,移除公开的目录枚举接口。</li>
|
||||
<li>监控默认仅开放汇总健康状态。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="release-group">
|
||||
<h4>升级重点</h4>
|
||||
<ul class="release-list">
|
||||
<li>建议 v5.0.2 及更早版本用户升级,继续要求 JDK 21 及以上。</li>
|
||||
<li>已有外部配置需将 <code>management.endpoints.web.exposure.include</code> 设为 <code>health</code>,将 <code>management.endpoint.health.show-details</code> 设为 <code>never</code>。</li>
|
||||
<li><code>/directory</code> 接口已移除,内置压缩包预览继续可用。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="release-card">
|
||||
<h3>v5.0.2</h3>
|
||||
<div class="release-meta">
|
||||
<span class="tag brand">2026-08-14</span>
|
||||
<span class="tag highlight">最新稳定版本</span>
|
||||
<span class="tag">上一补丁版本</span>
|
||||
<span class="tag warn">建议尽快升级</span>
|
||||
</div>
|
||||
<div class="release-columns">
|
||||
|
||||
Reference in New Issue
Block a user