Skip to content

fix(security): move root temp files from /tmp to /run/lastore - #503

Merged
zhaohuiw42 merged 1 commit into
linuxdeepin:masterfrom
zhaohuiw42:fix/security-run-lastore-temp-files
Oct 22, 2026
Merged

zhaohuiw42 merged 1 commit into
linuxdeepin:masterfrom
zhaohuiw42:fix/security-run-lastore-temp-files

Conversation

@zhaohuiw42

@zhaohuiw42 zhaohuiw42 commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Backport the 5.6.21 -> 5.6.22 temp-file hardening to master.

  • Move root temp files from /tmp to the root-only /run/lastore runtime dir: checkpolicy cache, job cache, apt download dir, combined source dirs, coreList extraction, custom repo list, InRelease staging, platform report xz/tar, and masked logs.
  • Add utils.RuntimeDirPath, EnsureSecureDir and EnsureRuntimeDir; verify directory ownership and mode before writing.
  • Read the checkpolicy cache with O_NOFOLLOW|O_NONBLOCK and write it atomically with mode 0600.
  • Stop reading the legacy /tmp/platform_cache.json and /tmp/classified_cache.json fallbacks.
  • Remove the obsolete readCacheWithLegacyFallback helper and its tests.
  • Isolate tests from /run/lastore; the checkpolicy smoke test no longer calls UpdateSource.

Verification

  • go build ./... passes.
  • go test ./... passes for all packages.

PMS: BUG-378545

Summary by Sourcery

Harden root temporary-file handling by replacing predictable /tmp paths with validated, root-only runtime storage.

Bug Fixes:

  • Move root-owned temporary files and caches out of globally writable /tmp to the secure /run/lastore runtime directory.
  • Harden check-policy cache access against symlink and FIFO attacks and write it atomically with restrictive permissions.
  • Stop using legacy /tmp platform and classified cache fallbacks.

Enhancements:

  • Add secure runtime-directory validation and centralize runtime temporary-file handling across package downloads, source files, reports, logs, and daemon caches.

Tests:

  • Update tests to isolate runtime-directory state in secure temporary directories and cover secure directory and check-policy cache behavior.

Chores:

  • Remove the obsolete legacy cache fallback helper and its tests.

Root temp files used predictable or world-writable /tmp paths. Move
them to the root-only runtime dir, verify its ownership and mode
before each write, reject symlinks when reading the checkpolicy
cache, and drop the legacy /tmp cache fallback. Tests isolate the
runtime dir and no longer call UpdateSource.

Log: harden temp file paths
PMS: BUG-378545
Influence: Temp files for update checks, repo config, downloads,
platform reports and log masking now live in /run/lastore. Legacy
/tmp caches are ignored, so the first check after upgrade re-triggers
UpdateSource once. Writes are rejected when the dir is not owned by
the current user or is writable by others.
@sourcery-ai

sourcery-ai Bot commented Oct 20, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR backports temp-file hardening by replacing root-owned predictable paths under /tmp with validated, private /run/lastore storage, hardening checkpolicy cache reads and atomic writes, removing unsafe legacy cache fallbacks, and updating tests to isolate and verify the new runtime-directory contract.

Sequence diagram for hardened checkpolicy cache handling

sequenceDiagram
    participant Tool as lastore-tools checkpolicy
    participant Cache as checkpolicy.cache
    participant Runtime as /run/lastore
    participant System as system bus

    Tool->>Cache: readCheckPolicyCache
    Cache-->>Tool: O_NOFOLLOW and O_NONBLOCK read
    Tool->>Tool: genVersionResponse
    alt policy changed
        Tool->>Runtime: EnsureSecureDir
        Tool->>Cache: writeCheckPolicyCache
        Cache-->>Tool: atomic 0600 update
        Tool->>System: notify policy change
    end
Loading

Flow diagram for root temporary-file hardening

flowchart TD
    Start[Root operation needs temporary storage]
    Validate[EnsureRuntimeDir]
    Check{Directory is owned by current user and not group or world writable?}
    Secure["/run/lastore"]
    Fail[Abort operation]
    Cleanup[Remove temporary artifact]

    Start --> Validate
    Validate --> Check
    Check -- No --> Fail
    Check -- Yes --> Secure
    Secure --> Cleanup
Loading

File-Level Changes

Change Details Files
Centralize root-only runtime temporary storage and validate its security before use.
  • Introduce a configurable /run/lastore path with ownership and permission checks.
  • Migrate apt downloads, combined source directories, core-list extraction, job/unit/agent caches, custom repository files, platform reports, staged InRelease files, and masked logs out of /tmp.
  • Redirect tests to secure temporary runtime directories and add coverage for directory validation.
src/internal/utils/utils.go
src/internal/utils/utils_test.go
src/internal/system/apt/apt.go
src/internal/system/update_type.go
src/lastore-daemon/agent.go
src/lastore-daemon/manager_idle.go
src/lastore-daemon/manager_unit.go
src/lastore-daemon/manager_ifc.go
src/lastore-daemon/common.go
src/internal/updateplatform/message_report.go
src/lastore-tools/update_message.go
src/lastore-daemon/runtime_dir_test.go
src/internal/system/runtime_dir_extra_test.go
src/internal/system/apt/download_extra_test.go
src/internal/system/coverage_extra_test.go
src/internal/system/update_type_source_dir_extra_test.go
src/lastore-daemon/agent_extra_test.go
src/lastore-daemon/manager_logic_extra_test.go
src/lastore-daemon/manager_test.go
src/lastore-daemon/manager_idle_extra_test.go
src/internal/updateplatform/http_flow_extra_test.go
src/lastore-tools/update_message_extra_test.go
src/lastore-tools/update_message_monitor_extra_test.go
Harden checkpolicy cache handling against symlink, FIFO, and partial-write attacks.
  • Move the checkpolicy cache to the runtime directory and remove legacy /tmp cache fallbacks.
  • Read with `O_NOFOLLOW
O_NONBLOCK` and reject non-regular files.
  • Write through secure atomic file replacement with mode 0600.
  • Remove insecure legacy cache compatibility and improve temporary-file cleanup.
    • Delete the legacy cache fallback helper and its tests.
    • Clean failed apt downloads and successfully consumed core-list packages.
    • Remove generated report and log archives after use where applicable.
    src/internal/config/config.go
    src/internal/config/config_test.go
    src/internal/config/config_cache_extra_test.go
    src/internal/system/apt/apt.go
    src/lastore-daemon/common.go
    src/internal/updateplatform/message_report.go

    Tips and commands

    Interacting with Sourcery

    • Trigger a new review: Comment @sourcery-ai review on the pull request.
    • Continue discussions: Reply directly to Sourcery's review comments.
    • Generate a GitHub issue from a review comment: Ask Sourcery to create an
      issue from a review comment by replying to it. You can also reply to a
      review comment with @sourcery-ai issue to create an issue from it.
    • Generate a pull request title: Write @sourcery-ai anywhere in the pull
      request title to generate a title at any time. You can also comment
      @sourcery-ai title on the pull request to (re-)generate the title at any time.
    • Generate a pull request summary: Write @sourcery-ai summary anywhere in
      the pull request body to generate a PR summary at any time exactly where you
      want it. You can also comment @sourcery-ai summary on the pull request to
      (re-)generate the summary at any time.
    • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
      request to (re-)generate the reviewer's guide at any time.
    • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
      pull request to resolve all Sourcery comments. Useful if you've already
      addressed all the comments and don't want to see them anymore.
    • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
      request to dismiss all existing Sourcery reviews. Especially useful if you
      want to start fresh with a new review - don't forget to comment
      @sourcery-ai review to trigger a new review!

    Customizing Your Experience

    Access your dashboard to:

    • Enable or disable review features such as the Sourcery-generated pull request
      summary, the reviewer's guide, and others.
    • Change the review language.
    • Add, remove or edit custom review instructions.
    • Adjust other review settings.

    Getting Help

    @github-actions

    Copy link
    Copy Markdown

    CLA Assistant Lite bot:
    提交邮箱中包含我们的合作伙伴,但您似乎并非合作伙伴的成员或对接人,请联系相关对接人将您添加至组织之中,或由其重新发起 Pull Request。
    The commit email domain belongs to one of our partners, but it seems you are not yet a member of the current organization, please contact the contact person to add you to the organization or let them submit the Pull Request.

    You can retrigger this bot by commenting recheck in this Pull Request

    @sourcery-ai sourcery-ai Bot left a comment

    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Hey - I've found 7 issues

    Prompt for AI Agents
    Please address the comments from this code review:
    
    ## Individual Comments
    
    ### Comment 1
    <location path="src/lastore-daemon/manager_ifc.go" line_range="637" />
    <code_context>
    +			logger.Warning(err)
    +			return dbusutil.ToError(err)
    +		}
    +		tmpFile, err := os.CreateTemp(utils.RuntimeDirPath, "custom_repo_*.list")
     		if err != nil {
     			logger.Warning(err)
    </code_context>
    <issue_to_address>
    **Upgrade options remain in /tmp**
    
    When a fullscreen upgrade is prepared while an unprivileged local user can modify `/tmp`, `PrepareFullScreenUpgrade` still renames the option file to `/tmp/deepin_update_option.json` (`manager_check.go:195`), where an unprivileged user can replace the fixed pathname before the upgrade consumer reads it. Root can then consume attacker-controlled upgrade options, despite the new custom-repository temp file using the protected runtime directory.
    
    Move the fullscreen-upgrade option file and its consumer to a path in the secured runtime directory, validating that directory before use.
    </issue_to_address>
    
    ### Comment 2
    <location path="src/internal/utils/utils.go" line_range="208" />
    <code_context>
    +	if !fi.IsDir() {
    +		return fmt.Errorf("%s is not a directory", dir)
    +	}
    +	if fi.Mode().Perm()&0022 != 0 {
    +		return fmt.Errorf("%s mode %#o is writable by other users", dir, fi.Mode().Perm())
    +	}
    </code_context>
    <issue_to_address>
    **Runtime files remain readable**
    
    When the runtime directory exists with mode 0755, `EnsureSecureDir` rejects write permissions but accepts group/world read and execute permissions. Callers can then create files such as the log archive there, allowing other local users to list the directory and read those files.
    
    Require the runtime directory to have no group or world permissions.
    </issue_to_address>
    
    ### Comment 3
    <location path="src/lastore-daemon/common.go" line_range="476" />
    <code_context>
    +		if err := utils.EnsureRuntimeDir(); err != nil {
    +			return "", err
    +		}
    +		tmpDir, err := os.MkdirTemp(utils.RuntimeDirPath, coreListPkgName+".XXXXXX")
     		if err != nil {
     			return "", err
    </code_context>
    <issue_to_address>
    **Core-list extractions fill runtime storage**
    
    When core-list downloads or extractions succeed repeatedly, `downloadAndDecompressCoreList` creates an extraction directory and returns a file inside it, but `getCoreListOnline` does not remove the directory after reading or copying the file. The extracted trees accumulate in `/run/lastore` until runtime storage is consumed and other temporary-file operations fail.
    
    Remove each extraction directory after its caller has finished using the returned file, including on error paths.
    </issue_to_address>
    
    ### Comment 4
    <location path="src/internal/system/apt/apt.go" line_range="288" />
    <code_context>
    +	if err := utils.EnsureRuntimeDir(); err != nil {
    +		return "", err
    +	}
    +	tmpPath, err := os.MkdirTemp(utils.RuntimeDirPath, "apt-download-")
     	if err != nil {
     		return "", err
    </code_context>
    <issue_to_address>
    **Large downloads exhaust runtime storage**
    
    When an apt download exceeds the space available in `/run`, `DownloadPackages` places all downloaded packages under `/run/lastore`, which is typically a size-limited tmpfs. When a package set exceeds the space available there, `apt-get` fails with ENOSPC and the update or core-list download fails.
    
    Keep security-sensitive staging in `/run/lastore`, but place potentially large package downloads in a protected disk-backed directory with safe creation and ownership checks.
    </issue_to_address>
    
    ### Comment 5
    <location path="src/lastore-daemon/manager_idle.go" line_range="24" />
    <code_context>
    +// 原路径为 /tmp/lastoreJobCache.json:/tmp 全局可写且文件名固定,本地用户可抢先
    +// 创建同名符号链接/文件,诱导 root 守护进程读写其指定对象;/run/lastore 为 root 独占目录。
    +// 保留为变量以便测试重定向。
    +var lastoreJobCacheJson = filepath.Join(utils.RuntimeDirPath, "lastoreJobCache.json")
    
     func (m *Manager) canAutoQuit() bool {
    </code_context>
    <issue_to_address>
    **Saved jobs disappear after reboot**
    
    When the daemon saves failed or paused jobs and the machine reboots before they are restored, `loadCacheJob` reads the relocated cache from `/run/lastore`, but `/run` is cleared on reboot and the old `/tmp` cache is not migrated or read, so saved failed or paused jobs are not restored after a reboot.
    
    Store this restart/reboot recovery cache in persistent state, or migrate it to a persistent location and read it there on startup.
    </issue_to_address>
    
    ### Comment 6
    <location path="src/lastore-daemon/manager_logic_extra_test.go" line_range="157" />
    <code_context>
    
     func TestSaveCacheJob_EmptyJobList(t *testing.T) {
    +	oldCache := lastoreJobCacheJson
    +	lastoreJobCacheJson = filepath.Join(secureTempDir(t), "lastoreJobCache.json")
    +	t.Cleanup(func() { lastoreJobCacheJson = oldCache })
    +
    </code_context>
    <issue_to_address>
    **Failed job omission passes**
    
    When `saveCacheJob` writes a cache file but omits the failed job, `TestSaveCacheJob_WithFailedJob` only calls `assert.FileExists` at line 171, so an implementation that writes an empty job list instead of saving the failed job still passes.
    
    Read and unmarshal the cache, then assert it contains the expected job ID and failed status.
    </issue_to_address>
    
    ### Comment 7
    <location path="src/internal/system/apt/download_extra_test.go" line_range="43" />
    <code_context>
     }
    
     func TestDownloadPackagesSuccess(t *testing.T) {
    +	redirectRuntimeDir(t)
     	prependFakeAptGet(t, 0, "")
    
    </code_context>
    <issue_to_address>
    **Apt path regression passes**
    
    When `DownloadPackages` returns a nonempty path outside `utils.RuntimeDirPath`, `TestDownloadPackagesSuccess` only checks `assert.NotEmpty(t, tmpPath)` at line 48, so a regression that creates the download directory outside `utils.RuntimeDirPath` still passes and the test misses the required relocation.
    
    Assert that `tmpPath` exists and is a child of `utils.RuntimeDirPath`.
    </issue_to_address>

    Sourcery is free for open source - if you like our reviews please consider sharing them ✨

    logger.Warning(err)
    return dbusutil.ToError(err)
    }
    tmpFile, err := os.CreateTemp(utils.RuntimeDirPath, "custom_repo_*.list")

    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    🟠 High · Upgrade options remain in /tmp

    When a fullscreen upgrade is prepared while an unprivileged local user can modify /tmp, PrepareFullScreenUpgrade still renames the option file to /tmp/deepin_update_option.json (manager_check.go:195), where an unprivileged user can replace the fixed pathname before the upgrade consumer reads it. Root can then consume attacker-controlled upgrade options, despite the new custom-repository temp file using the protected runtime directory.

    Move the fullscreen-upgrade option file and its consumer to a path in the secured runtime directory, validating that directory before use.

    Prompt for AI agents
    In `src/lastore-daemon/manager_ifc.go` at line 637:
    
    **Upgrade options remain in /tmp**
    
    When a fullscreen upgrade is prepared while an unprivileged local user can modify `/tmp`, `PrepareFullScreenUpgrade` still renames the option file to `/tmp/deepin_update_option.json` (`manager_check.go:195`), where an unprivileged user can replace the fixed pathname before the upgrade consumer reads it. Root can then consume attacker-controlled upgrade options, despite the new custom-repository temp file using the protected runtime directory.
    
    Move the fullscreen-upgrade option file and its consumer to a path in the secured runtime directory, validating that directory before use.

    if !fi.IsDir() {
    return fmt.Errorf("%s is not a directory", dir)
    }
    if fi.Mode().Perm()&0022 != 0 {

    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    🟡 Medium · Runtime files remain readable

    When the runtime directory exists with mode 0755, EnsureSecureDir rejects write permissions but accepts group/world read and execute permissions. Callers can then create files such as the log archive there, allowing other local users to list the directory and read those files.

    Require the runtime directory to have no group or world permissions.

    Prompt for AI agents
    In `src/internal/utils/utils.go` at line 208:
    
    **Runtime files remain readable**
    
    When the runtime directory exists with mode 0755, `EnsureSecureDir` rejects write permissions but accepts group/world read and execute permissions. Callers can then create files such as the log archive there, allowing other local users to list the directory and read those files.
    
    Require the runtime directory to have no group or world permissions.

    if err := utils.EnsureRuntimeDir(); err != nil {
    return "", err
    }
    tmpDir, err := os.MkdirTemp(utils.RuntimeDirPath, coreListPkgName+".XXXXXX")

    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    🟡 Medium · Core-list extractions fill runtime storage

    When core-list downloads or extractions succeed repeatedly, downloadAndDecompressCoreList creates an extraction directory and returns a file inside it, but getCoreListOnline does not remove the directory after reading or copying the file. The extracted trees accumulate in /run/lastore until runtime storage is consumed and other temporary-file operations fail.

    Remove each extraction directory after its caller has finished using the returned file, including on error paths.

    Prompt for AI agents
    In `src/lastore-daemon/common.go` at line 476:
    
    **Core-list extractions fill runtime storage**
    
    When core-list downloads or extractions succeed repeatedly, `downloadAndDecompressCoreList` creates an extraction directory and returns a file inside it, but `getCoreListOnline` does not remove the directory after reading or copying the file. The extracted trees accumulate in `/run/lastore` until runtime storage is consumed and other temporary-file operations fail.
    
    Remove each extraction directory after its caller has finished using the returned file, including on error paths.

    if err := utils.EnsureRuntimeDir(); err != nil {
    return "", err
    }
    tmpPath, err := os.MkdirTemp(utils.RuntimeDirPath, "apt-download-")

    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    🟡 Medium · Large downloads exhaust runtime storage

    When an apt download exceeds the space available in /run, DownloadPackages places all downloaded packages under /run/lastore, which is typically a size-limited tmpfs. When a package set exceeds the space available there, apt-get fails with ENOSPC and the update or core-list download fails.

    Keep security-sensitive staging in /run/lastore, but place potentially large package downloads in a protected disk-backed directory with safe creation and ownership checks.

    Prompt for AI agents
    In `src/internal/system/apt/apt.go` at line 288:
    
    **Large downloads exhaust runtime storage**
    
    When an apt download exceeds the space available in `/run`, `DownloadPackages` places all downloaded packages under `/run/lastore`, which is typically a size-limited tmpfs. When a package set exceeds the space available there, `apt-get` fails with ENOSPC and the update or core-list download fails.
    
    Keep security-sensitive staging in `/run/lastore`, but place potentially large package downloads in a protected disk-backed directory with safe creation and ownership checks.

    // 原路径为 /tmp/lastoreJobCache.json:/tmp 全局可写且文件名固定,本地用户可抢先
    // 创建同名符号链接/文件,诱导 root 守护进程读写其指定对象;/run/lastore 为 root 独占目录。
    // 保留为变量以便测试重定向。
    var lastoreJobCacheJson = filepath.Join(utils.RuntimeDirPath, "lastoreJobCache.json")

    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    🟡 Medium · Saved jobs disappear after reboot

    When the daemon saves failed or paused jobs and the machine reboots before they are restored, loadCacheJob reads the relocated cache from /run/lastore, but /run is cleared on reboot and the old /tmp cache is not migrated or read, so saved failed or paused jobs are not restored after a reboot.

    Store this restart/reboot recovery cache in persistent state, or migrate it to a persistent location and read it there on startup.

    Prompt for AI agents
    In `src/lastore-daemon/manager_idle.go` at line 24:
    
    **Saved jobs disappear after reboot**
    
    When the daemon saves failed or paused jobs and the machine reboots before they are restored, `loadCacheJob` reads the relocated cache from `/run/lastore`, but `/run` is cleared on reboot and the old `/tmp` cache is not migrated or read, so saved failed or paused jobs are not restored after a reboot.
    
    Store this restart/reboot recovery cache in persistent state, or migrate it to a persistent location and read it there on startup.


    func TestSaveCacheJob_WithFailedJob(t *testing.T) {
    oldCache := lastoreJobCacheJson
    lastoreJobCacheJson = filepath.Join(secureTempDir(t), "lastoreJobCache.json")

    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    🟡 Medium · Failed job omission passes

    When saveCacheJob writes a cache file but omits the failed job, TestSaveCacheJob_WithFailedJob only calls assert.FileExists at line 171, so an implementation that writes an empty job list instead of saving the failed job still passes.

    Read and unmarshal the cache, then assert it contains the expected job ID and failed status.

    Prompt for AI agents
    In `src/lastore-daemon/manager_logic_extra_test.go` at line 157:
    
    **Failed job omission passes**
    
    When `saveCacheJob` writes a cache file but omits the failed job, `TestSaveCacheJob_WithFailedJob` only calls `assert.FileExists` at line 171, so an implementation that writes an empty job list instead of saving the failed job still passes.
    
    Read and unmarshal the cache, then assert it contains the expected job ID and failed status.

    }

    func TestDownloadPackagesSuccess(t *testing.T) {
    redirectRuntimeDir(t)

    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    🟡 Medium · Apt path regression passes

    When DownloadPackages returns a nonempty path outside utils.RuntimeDirPath, TestDownloadPackagesSuccess only checks assert.NotEmpty(t, tmpPath) at line 48, so a regression that creates the download directory outside utils.RuntimeDirPath still passes and the test misses the required relocation.

    Assert that tmpPath exists and is a child of utils.RuntimeDirPath.

    Prompt for AI agents
    In `src/internal/system/apt/download_extra_test.go` at line 43:
    
    **Apt path regression passes**
    
    When `DownloadPackages` returns a nonempty path outside `utils.RuntimeDirPath`, `TestDownloadPackagesSuccess` only checks `assert.NotEmpty(t, tmpPath)` at line 48, so a regression that creates the download directory outside `utils.RuntimeDirPath` still passes and the test misses the required relocation.
    
    Assert that `tmpPath` exists and is a child of `utils.RuntimeDirPath`.

    @deepin-ci-robot

    Copy link
    Copy Markdown

    deepin pr auto review

    🤖 AI 代码审查报告

    总体评分: 100 分 (通过阈值: 70分)

    Pass


    📊 总体评价

    项目 结果
    审查结论 代码审查通过
    评分详情 本次提交是一个安全修复,将 lastore-daemon 及 lastore-tools 中 root 进程使用的临时文件 从全局可写的 /tmp 迁移到 root 独占的 /run/lastore(0700),消除了本地用户通过预置 可预测路径的符号链接/命名管道/普通文件来诱导 root 进程读写指定对象的攻击面。新增了 EnsureSecureDir 安全目录校验函数(验证目录类型、权限位、属主),在读取缓存时使用 O_NOFOLLOW

    🔍 详细分析

    1. 语法逻辑 ✅

    评价: 语法正确,逻辑清晰 ✅ 通过

    潜在问题:
    ✅ 未发现明显问题

    建议: []


    2. 代码质量 ✅

    评价: 代码结构清晰,注释完整 ✅ 通过

    潜在问题:
    ✅ 未发现明显问题

    建议: []


    3. 代码性能 ✅

    评价: 性能良好,资源使用合理 ✅ 通过

    潜在问题:
    ✅ 未发现明显问题

    建议: []


    4. 代码安全 🔒

    评价: 存在0个安全漏洞 ✅ 通过

    🔐 发现 0 个安全漏洞

    安全漏洞详情:
    ✅ 未发现安全漏洞

    建议: ['建议后续考虑将 WriteFileSecurely 内部的 MkdirAll 权限从 0755 收紧为 0700, 使其与 EnsureSecureDir 的安全策略一致,减少对调用方先调用 EnsureSecureDir 的隐式依赖。']


    💡 改进建议代码示例

    // 当前代码已正确实现安全修复,无需额外修改。
    // 以下为 WriteFileSecurely 内部 MkdirAll 权限收紧的改进建议:
    //
    // func WriteFileSecurely(path string, content []byte, perm os.FileMode) error {
    //     dir := filepath.Dir(path)
    //     if err := os.MkdirAll(dir, 0700); err != nil {  // 从 0755 收紧为 0700
    //         return err
    //     }
    //     // ... 其余逻辑不变
    // }

    本报告由 AI 代码审查工具自动生成

    @deepin-ci-robot

    Copy link
    Copy Markdown

    [APPROVALNOTIFIER] This PR is NOT APPROVED

    This pull-request has been approved by: qiuzhiqian, zhaohuiw42

    The full list of commands accepted by this bot can be found here.

    Details Needs approval from an approver in each of these files:

    Approvers can indicate their approval by writing /approve in a comment
    Approvers can cancel approval by writing /approve cancel in a comment

    @zhaohuiw42
    zhaohuiw42 merged commit 9083b2a into linuxdeepin:master Oct 22, 2026
    11 of 13 checks passed
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Labels

    None yet

    Projects

    None yet

    Development

    Successfully merging this pull request may close these issues.

    3 participants