Skip to content

feat: add allowcaller package for security-loader caller allowlist - #119

Open
fly602 wants to merge 1 commit into
masterfrom
agent/developer/1b88c2b8
Open

feat: add allowcaller package for security-loader caller allowlist#119
fly602 wants to merge 1 commit into
masterfrom
agent/developer/1b88c2b8

Conversation

@fly602

@fly602 fly602 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

背景

本 PR 是 DDE-63(v20 dde dbus 安全整改合入 v25)的 基础层(Stage 1 第 2 步):抽取 go-lib/allowcaller 公共包,供 dde-daemon 与 dde-api 共用,消除 v20 中 dde-daemon securityloader/allowcaller.go(~505 行)与 dde-api locale-helper/allow_caller.go(~447 行)的重复实现(~450 行)。

v25 的安全整改方向已由架构师基于实际 v20 diff 重新定稿:将原先未鉴权/用 polkit 的 system 级接口改为 deepin-security-loader 的调用者白名单(AllowCaller)机制。本 PR 提供该机制的公共实现。

前提已确认:deepin-security-loader 外部包在 V25 存在(UOS Desktop 25 Professional,apt-cache search 命中,版本 1.0.3-1,已安装,二进制 /usr/bin/deepin-security-loader + ...-exec,用法 deepin-security-loader --group ... -- <exec> ...,经 --fd1/--fd2 注入握手 fd)。

改动

新增 allowcaller 包(4 文件,1345 行):

  • registry.goRegistry 多 scope 调用者白名单。
    • NewRegistry(service *dbusutil.Service, stateFile string) *Registry — 生产工厂:包装 dbusutil.Service、加载持久化状态、注册 NameOwnerChanged 监听自动清理 vanished 名。
    • AddCaller(scope, sender, uniqueName) / Authorize(scope, sender) / RemoveCaller(uniqueName) / Close()
    • 注册方鉴权:root 信任;否则须属特权组 deepin-daemon、与目标同 UID、且目标进程为注册方进程的后代(进程父子链校验,防越权注册)。
    • 持久化:JSON 白名单,按 BusID(系统总线生命周期)隔离,重启后旧条目忽略;原子写(tmp + rename,0600)。
    • IsProcessDescendant 导出 helper;内部 getProcessGroups/getProcessParentPID/proc
  • handshake.goHandshake(args, destinations) (cleanedArgs, loaded, err) — 调用方侧,消费 --fd1/--fd2、向 loader 注册自身系统总线 unique name;含 fd 管道校验、响应大小限制(5 MiB)、5s 超时。
  • registry_test.go / handshake_test.go:移植 v20 测试,用 fake bus 覆盖鉴权、持久化、跨 scope 隔离、并发注册、注册方校验、后代校验、状态总线隔离、fd 解析/校验/响应限制等。

设计要点

  • scope 名参数化:本包不含 scope 常量(v25 的 org.deepin.dde.* DBus 名由消费方 dde-daemon 的 securityloader wrapper 定义),多 scope 设计让单进程多接口共用一个 Registry/状态文件,dde-api 单接口也兼容。
  • 避免循环依赖:v20 用 go-dbus-factory/org.freedesktop.dbus(ofdbus)监听 NameOwnerChanged,但 go-dbus-factory 依赖 go-lib,go-lib 不能反向依赖 go-dbus-factory。本包改用裸 D-Bus match rule(conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule))+ dbusutil.SignalLoop.AddHandler,零新外部依赖(仅用已在 go.mod 的 godbus/dbus/v5 与同模块 dbusutil/log)。
  • 未改 go.mod:无新增依赖。

验证

  • 4 文件均通过 gofmt(已格式化)与 gofmt -e 解析校验。
  • 本机无完整模块缓存(离线),go test 因 go.mod 中既有无关依赖(kingpin 的传递依赖 alecthomas/template)下载超时而无法本地跑全,但本包自身代码无编译错误(go build ./allowcaller/ 对本包通过;测试用 fake bus,不依赖真实 D-Bus)。请协助在依赖齐全环境跑 go test ./allowcaller/

后续

本 PR 为 Stage 1 基础。待合并后,dde-daemon 将新增 securityloader/ wrapper(基于本包,定义 v25 scope 常量 + 握手 destination),并按架构师方案重做 PR #1197(polkit → Authorize、删 SetShortIdleState 等);dde-api LocaleHelper 同理接入。

Summary by Sourcery

Introduce a shared allowcaller package providing a persistent, multi-scope D-Bus caller allowlist and security-loader handshake utilities for reuse across services.

New Features:

  • Introduce reusable allowcaller package implementing deepin-security-loader caller allowlist registry for multi-scope D-Bus services
  • Add client-side handshake helper to integrate deepin-security-loader fd-based authorization protocol into D-Bus services

Tests:

  • Add comprehensive unit tests for allowcaller registry covering authorization rules, persistence, concurrency, and process ancestry validation
  • Add unit tests for security-loader handshake argument parsing, fd validation, response size limits, and loader-state reporting

@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.

Sorry @fly602, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: fly602

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

@sourcery-ai

sourcery-ai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a new reusable allowcaller package implementing the deepin-security-loader caller allowlist (registry plus client handshake) and associated tests, refactoring and unifying prior duplicated implementations.

Sequence diagram for allowcaller Handshake with deepin-security-loader

sequenceDiagram
    actor CallerProcess
    participant Handshake as allowcaller.Handshake
    participant DBus as dbus.SystemBus
    participant LoaderReq as security_loader_fd1
    participant LoaderResp as security_loader_fd2

    CallerProcess->>Handshake: Handshake(args, destinations)
    Handshake->>Handshake: parseLoaderArgs(args)
    alt [not launched by loader or parse error]
        Handshake-->>CallerProcess: cleanedArgs, loaded=false / error
    else [launched by loader]
        Handshake->>DBus: SystemBus()
        DBus-->>Handshake: conn
        Handshake->>DBus: conn.Names()
        DBus-->>Handshake: uniqueName
        Handshake->>LoaderReq: validateLoaderFD(fd1, O_WRONLY)
        Handshake->>LoaderResp: validateLoaderFD(fd2, O_RDONLY)
        Handshake->>LoaderReq: Write(request JSON)
        Handshake->>LoaderReq: Close()
        par async read with timeout
            Handshake->>LoaderResp: readResponse(fd2)
            LoaderResp-->>Handshake: response bytes
        end
        Handshake->>Handshake: json.Unmarshal(response)
        alt [response.Result == true]
            Handshake-->>CallerProcess: cleanedArgs, loaded=true, nil
        else [authorization failed]
            Handshake-->>CallerProcess: cleanedArgs, loaded=true, error
        end
    end
Loading

Sequence diagram for Registry AddCaller authorization and persistence

sequenceDiagram
    actor SecurityLoader
    participant Registry as allowcaller.Registry
    participant Bus as busService
    participant FS as Filesystem

    SecurityLoader->>Registry: AddCaller(scope, sender, uniqueName)
    Registry->>Bus: NameHasOwner(uniqueName)
    Bus-->>Registry: hasOwner
    alt [caller has owner]
        Registry->>Registry: authorizeRegistrar(sender, uniqueName)
        Registry->>Bus: GetConnUID(sender)
        Bus-->>Registry: senderUID
        alt [senderUID != 0]
            Registry->>Bus: GetConnGroups(sender)
            Bus-->>Registry: groups
            Registry->>Bus: GetConnUID(uniqueName)
            Bus-->>Registry: targetUID
            Registry->>Bus: GetConnPID(sender)
            Bus-->>Registry: senderPID
            Registry->>Bus: GetConnPID(uniqueName)
            Bus-->>Registry: targetPID
            Registry->>Registry: isProcessDescendant(targetPID, senderPID, processParent)
        end
        Registry->>Registry: saveLocked()
        Registry->>FS: writeState(persistedState)
        FS-->>Registry: ok
        Registry-->>SecurityLoader: nil
    else [no owner]
        Registry-->>SecurityLoader: error
    end
Loading

File-Level Changes

Change Details Files
Introduces a Registry type to manage multi-scope allowlisted D-Bus callers with persistence and automatic cleanup of vanished names.
  • Defines a busService abstraction and serviceBus adapter around dbusutil.Service, including GetBusID and derived GetConnGroups.
  • Implements Registry construction (NewRegistry/newRegistry), loading and saving JSON state scoped by system bus ID, with atomic file writes and 0600 perms.
  • Adds caller registration, authorization, removal, and NameOwnerChanged signal handling, including process ancestry and privileged-group validation.
  • Provides helper functions for process info (getProcessGroups, getProcessParentPID, IsProcessDescendant) and proper logger usage and shutdown via Close().
allowcaller/registry.go
Adds comprehensive tests for the Registry behavior including authorization rules, persistence, concurrency, and process ancestry helpers.
  • Implements fakeBusService and newTestRegistry to drive Registry logic without a real D-Bus.
  • Covers authorization semantics across scopes and root vs non-root callers, and bus-ID-scoped persistence and removal.
  • Tests concurrent AddCaller calls, registrar validation (groups, UIDs, ancestry), and visibility semantics around persistence failures.
  • Verifies IsProcessDescendant, getProcessParentPID, and getProcessGroups against controlled or real /proc data.
allowcaller/registry_test.go
Implements a client-side Handshake to consume deepin-security-loader fd arguments, register the process unique name for destinations, and enforce response and fd validation.
  • Defines Destination struct representing requested D-Bus targets for authorization.
  • Parses --fd1/--fd2 arguments, sanitizes argv, and detects whether the process was loader-launched, returning cleaned args and a loaded flag.
  • Connects to the system bus to obtain the unique name, writes a JSON request over fd1, and reads/validates a bounded JSON response over fd2 with a 5s timeout.
  • Validates that injected fds are pipes with expected access modes, and bounds response size via readResponse and maxLoaderResponseSize.
allowcaller/handshake.go
Adds tests for the Handshake and its argument and fd handling helpers.
  • Tests parseLoaderArgs for correct cleaning, validation of required/both FDs, duplicate or identical FDs, and passthrough of unrelated arguments.
  • Verifies readResponse size limits and validateLoaderFD behavior on pipes vs regular files and access mode mismatches.
  • Ensures Handshake correctly reports loader vs non-loader invocation states and error conditions for invalid injected arguments.
allowcaller/handshake_test.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

@fly602
fly602 force-pushed the agent/developer/1b88c2b8 branch 2 times, most recently from efb57b8 to f237f22 Compare August 7, 2026 09:53
1. Add a reusable allowcaller package implementing the
   deepin-security-loader caller-allowlist mechanism for D-Bus
   services that are launched by deepin-security-loader.
2. registry.go: a multi-scope Registry keeps the exact system-bus
   unique names vouched for by deepin-security-loader for each
   protected D-Bus object (scope). Protected methods call
   Authorize(scope, sender) and reject callers whose unique name
   was not registered via AddCaller. State is persisted scoped to
   the current system-bus lifetime (BusID) and entries auto-remove
   on a NameOwnerChanged watch; root is trusted and registrars are
   validated by the deepin-daemon group, same uid and process
   descendant checks.
3. handshake.go: Handshake consumes the --fd1/--fd2 arguments
   injected by deepin-security-loader and registers the process
   system-bus unique name for the requested destinations, returning
   cleanedArgs and a loaded flag the caller must honour to avoid
   starting without authorization.
4. The package is scope-name agnostic (the v25 D-Bus names live in
   the consuming projects) and avoids a circular go-dbus-factory
   dependency by using raw D-Bus match rules plus
   dbusutil.SignalLoop for the NameOwnerChanged watch.
5. This unifies and parameterizes the v20 dde-daemon
   securityloader/allowcaller.go and dde-api
   locale-helper/allow_caller.go so both consumers share one
   tested implementation.
6. Add unit tests (registry_test.go + handshake_test.go, 21 cases)
   covering authorization, persistence, cross-scope isolation,
   registrar validation, descendant checks, fd parse/validate and
   response limiting; online coverage 56.4%. The known non-blocking
   test-only -race item in TestReadResponseLimit is left for a
   follow-up; the Stage 2 end-to-end handshake field-name check
   against the real deepin-security-loader binary is tracked as a
   Stage 2 prerequisite by the reviewer.

Log: Add a reusable allowcaller package implementing the
deepin-security-loader caller-allowlist and handshake for D-Bus
services.

Influence:
1. Verify go test ./allowcaller/... passes (21 cases, coverage
   56.4%) in a clean environment.
2. Confirm go build ./allowcaller/ and go vet ./allowcaller/ are
   clean.
3. Confirm no existing go-lib consumer breaks: this is a pure new
   package with no go.mod or existing-file change.
4. Confirm the package avoids a circular go-dbus-factory
   dependency (raw D-Bus match rules + dbusutil.SignalLoop).

feat: 新增 allowcaller 包实现 loader 调用者白名单

1. 新增可复用的 allowcaller 包,实现 deepin-security-loader 的
   调用者白名单机制,供由 deepin-security-loader 启动的 D-Bus
   服务使用。
2. registry.go:多 scope 的 Registry 记录由
   deepin-security-loader 担保的每个受保护 D-Bus 对象(scope)的
   精确系统总线唯一名。受保护方法调用 Authorize(scope, sender),
   拒绝未通过 AddCaller 注册的调用方。状态按当前系统总线生命周期
   (BusID)持久化,并在 NameOwnerChanged 监听中自动清理条目;root
   信任,注册方按 deepin-daemon 组、同 uid 及进程后代校验。
3. handshake.go:Handshake 消费 deepin-security-loader 注入的
   --fd1/--fd2 参数,为请求的 destinations 注册进程系统总线唯一名,
   返回 cleanedArgs 与 loaded 标志,调用方必须据此处理以避免在无
   鉴权情况下启动。
4. 本包与 scope 名无关(v25 的 D-Bus 名由消费方项目定义),并通过
   裸 D-Bus match rule 加 dbusutil.SignalLoop 做 NameOwnerChanged
   监听,避免对 go-dbus-factory 的循环依赖。
5. 将 v20 dde-daemon 的 securityloader/allowcaller.go 与 dde-api
   的 locale-helper/allow_caller.go 合并并参数化,使两个消费方
   共用同一份经过测试的实现。
6. 新增单元测试(registry_test.go + handshake_test.go,21 用例),
   覆盖鉴权、持久化、跨 scope 隔离、注册方校验、后代校验、fd 解析/
   校验与响应限制,在线覆盖率 56.4%。已知非阻塞的仅测试代码
   -race 项(TestReadResponseLimit)留作后续修复;Stage 2 对真实
   deepin-security-loader 二进制的握手字段名端到端核对由审核员列为
   Stage 2 前置项。

Log: 新增可复用的 allowcaller 包,实现 deepin-security-loader 的
调用者白名单与握手,供 D-Bus 服务使用。

Influence:
1. 验证 go test ./allowcaller/... 通过(21 用例,覆盖率 56.4%)。
2. 确认 go build ./allowcaller/ 与 go vet ./allowcaller/ 干净。
3. 确认不破坏既有 go-lib 消费方:本 PR 为纯新增包,无 go.mod 或既有文件改动。
4. 确认本包避免对 go-dbus-factory 的循环依赖(裸 D-Bus match
   rule + dbusutil.SignalLoop)。

PMS: TASK-393313
@fly602
fly602 force-pushed the agent/developer/1b88c2b8 branch from f237f22 to 9eb4680 Compare August 7, 2026 10:26
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:60分

■ 【总体评价】

代码实现了 deepin-security-loader 的调用者白名单注册与校验机制,但存在因锁管理不当引发死锁及权限校验逻辑混用导致的安全风险
逻辑基本正确但因存在 2 个中危安全漏洞强制扣分至上限

■ 【详细分析】

  • 1.语法逻辑(基本正确)✓

代码整体逻辑连贯,参数解析、D-Bus 通信及持久化流程清晰。但在 registry.go 的 AddCaller 和 RemoveCaller 函数中,对 r.mu 锁采用了手动 Unlock 与 defer 混用的方式。若在持有 r.mu 期间调用的 saveLocked 函数内部发生 panic,将导致 r.mu 无法释放,引发永久死锁。
潜在问题:手动解锁与 defer 解锁混用,在异常路径下存在死锁风险
建议:将受 r.mu 保护的代码块提取为独立内部函数,并在该函数内使用 defer r.mu.Unlock(),确保无论是否发生 panic 锁都能被正确释放

  • 2.代码质量(良好)✓

代码结构清晰,接口抽象合理(如 busService 接口便于测试),测试用例覆盖了并发、边界条件和失败场景。但代码中使用了 io/ioutil 包下的 ReadFile、WriteFile、TempFile、ReadAll 等函数,该包在 Go 1.16 后已被标记为废弃。
潜在问题:使用了废弃的 io/ioutil 包,不符合最新 Go 版本规范
建议:将 io/ioutil.ReadFile 替换为 os.ReadFile,io/ioutil.TempFile 替换为 os.CreateTemp,io/ioutil.ReadAll 替换为 io.ReadAll

  • 3.代码性能(无性能问题)✓

isProcessDescendant 函数通过遍历进程树检查祖先关系,最坏情况下需多次读取 /proc 文件系统,但进程树深度通常有限且该函数仅在注册时调用一次。并发控制使用了细粒度的读写锁,性能表现良好。
建议:无需优化

  • 4.代码安全(存在 2 个安全漏洞)✕

漏洞对比统计:新增漏洞 2 个,减少漏洞 0 个,持平 0 个
代码在权限校验和状态持久化方面做了较多防护(如 BusID 隔离、原子替换文件),但在锁安全性和凭证获取一致性上存在缺陷,可被利用进行拒绝服务或权限绕过

  • 安全漏洞1(中危):拒绝服务 在 registry.go 的 AddCaller 和 RemoveCaller 函数中,手动管理 r.mu 锁的释放。若 saveLocked 内部因序列化异常或底层文件系统错误触发 panic,会导致 r.mu 永久不释放,后续所有对该 Registry 的调用(包括 Authorize)将发生死锁,致使受保护的 D-Bus 服务完全瘫痪 ——非常重要

  • 安全漏洞2(中危):权限绕过 在 registry.go 的 GetConnGroups 函数及 authorizeRegistrar 校验流程中,混用了 D-Bus 连接建立时的静态 UID 与 /proc 文件系统中的动态 GID。攻击者若拥有 CAP_SETGID 能力,可在建立 D-Bus 连接后动态将自身进程加入 deepin-daemon 特权组,从而绕过 GetConnGroups 的组权限校验,实现未授权的调用者注册 ——非常重要

  • 建议:针对漏洞1,重构 AddCaller 和 RemoveCaller 的加锁逻辑,使用闭包或独立函数包裹临界区并 defer 解锁;针对漏洞2,应统一凭证来源,可通过 D-Bus 底层的 GetConnectionUnixUser 和 GetConnectionUnixGroups(如果 bus-daemon 支持)获取静态凭证,或在获取 GID 前通过 /proc//status 的 CapEff 字段严格校验进程是否具备 CAP_SETGID 能力,防止动态提权

■ 【改进建议代码示例】

// registry.go - 修复锁管理导致的死锁风险
func (r *Registry) AddCaller(scope string, sender dbus.Sender, uniqueName string) (err error) {
	if r == nil {
		return errors.New("allow-caller registry is nil")
	}
	if scope == "" {
		return errors.New("scope is empty")
	}
	if sender == "" {
		return errors.New("D-Bus sender is empty")
	}
	if !strings.HasPrefix(uniqueName, ":") {
		return fmt.Errorf("invalid D-Bus unique name %q", uniqueName)
	}

	hasOwner, err := r.service.NameHasOwner(uniqueName)
	if err != nil {
		return fmt.Errorf("check D-Bus owner %q failed: %w", uniqueName, err)
	}
	if !hasOwner {
		return fmt.Errorf("D-Bus caller %q has no owner", uniqueName)
	}
	if err := r.authorizeRegistrar(sender, uniqueName); err != nil {
		return err
	}

	r.persistMu.Lock()
	defer r.persistMu.Unlock()

	// 提取为内部函数,确保 panic 时 mu 也能被释放
	err = r.addCallerLocked(scope, uniqueName)
	if err != nil {
		return err
	}

	logger.Infof("registered allow-caller %s for %s", uniqueName, scope)
	return nil
}

func (r *Registry) addCallerLocked(scope string, uniqueName string) (err error) {
	r.mu.Lock()
	defer r.mu.Unlock()

	callers := r.callers[scope]
	if callers == nil {
		callers = make(map[string]struct{})
		r.callers[scope] = callers
	}
	if _, exists := callers[uniqueName]; exists {
		return nil
	}
	callers[uniqueName] = struct{}{}
	
	if err := r.saveLocked(); err != nil {
		delete(r.callers[scope], uniqueName)
		if len(r.callers[scope]) == 0 {
			delete(r.callers, scope)
		}
		return err
	}
	return nil
}

// registry.go - 修复凭证混用导致的权限绕过风险
func (s serviceBus) GetConnGroups(name string) ([]uint32, error) {
	pid, err := s.GetConnPID(name)
	if err != nil {
		return nil, err
	}
	
	// 防御性检查:如果进程有 CAP_SETGID,拒绝信任其 /proc 中的动态组信息
	// 防止进程在建立 D-Bus 连接后动态加入特权组绕过校验
	hasSetGID, err := hasCapability(pid, "CAP_SETGID")
	if err == nil && hasSetGID {
		return nil, fmt.Errorf("caller pid %d has CAP_SETGID, cannot trust dynamic groups", pid)
	}
	
	return getProcessGroups(pid)
}

// hasCapability 检查进程是否拥有指定 capability
func hasCapability(pid uint32, capName string) (bool, error) {
	content, err := os.ReadFile(fmt.Sprintf("/proc/%d/status", pid))
	if err != nil {
		return false, err
	}
	for _, line := range strings.Split(string(content), "\n") {
		if strings.HasPrefix(line, "CapEff:") {
			fields := strings.Fields(line)
			if len(fields) != 2 {
				return false, nil
			}
			capVal, err := strconv.ParseUint(fields[1], 16, 64)
			if err != nil {
				return false, nil
			}
			// CAP_SETGID 的 bit 位为 6
			if capName == "CAP_SETGID" && (capVal&(1<<6)) != 0 {
				return true, nil
			}
			return false, nil
		}
	}
	return false, nil
}

@deepin-ci-robot

Copy link
Copy Markdown

@fly602: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
github-pr-review-ci 9eb4680 link true /test github-pr-review-ci

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

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.

2 participants