From a539a4ff0517dd0b9c35b38b534892aada03f2d7 Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 13 Jul 2026 12:44:06 +0200 Subject: [PATCH] fix: render bounded webhook credential blockers --- .../R1.1_Task_Report.md | 3 +- .../src/platform-infra-gitea-config.test.ts | 55 +++++++++++++++++++ scripts/src/platform-infra-gitea-render.ts | 38 +++++++++++++ scripts/src/platform-infra-gitea.ts | 3 +- 4 files changed, 97 insertions(+), 2 deletions(-) diff --git a/docs/MDTODO/details/selfmedia-production-delivery/R1.1_Task_Report.md b/docs/MDTODO/details/selfmedia-production-delivery/R1.1_Task_Report.md index 469924ae..7f997041 100644 --- a/docs/MDTODO/details/selfmedia-production-delivery/R1.1_Task_Report.md +++ b/docs/MDTODO/details/selfmedia-production-delivery/R1.1_Task_Report.md @@ -29,11 +29,12 @@ ## Target 原入口证据 - 已通过 `trans NC01:/root/.worktrees/unidesk/selfmedia-repo-github-authority` 执行全部源码、Git 和验证操作。 -- `bun test scripts/src/platform-infra-gitea-config.test.ts scripts/src/platform-infra-gitea-disclosure.test.ts`:9 项通过,0 项失败。 +- `bun test scripts/src/platform-infra-gitea-config.test.ts scripts/src/platform-infra-gitea-disclosure.test.ts`:11 项通过,0 项失败。 - `bun scripts/cli.ts platform-infra gitea plan --target NC01`:policy 为 `ok`。 - `git diff --check`、Node 语法、Python `py_compile`、Shell `sh -n`:通过。 - `mirror bootstrap --target NC01 --repo selfmedia-nc01 --dry-run`:`OK=false`,blocker 为 `github-upstream:selfmedia-nc01`,符合 fail-closed。 - `mirror webhook status --target NC01 --repo selfmedia-nc01 --full`:在本地 credential blocker 处早返回,包含 `sourceRef`、`present=false`、`fingerprint=null`、`permissionResult=blocked-missing-credential` 与有界错误码;未访问运行面,JSON/stderr 均无 stack 或绝对 worktree 路径。 +- 默认 `mirror webhook status` compact 输出使用短表,按 `error.blockers` 精确匹配每个 credential/repository;带或不带 `--repo` 均只显示正确的 selfmedia blocker,`--full`/`--raw` 保持结构化。 - `mirror bootstrap --target JD01 --dry-run`:`OK=true`,证明 JD01 不依赖 NC01 override。 - 专用凭据只读状态:`sourceRef=pikainc-selfmedia-gh-token.txt`、`presence=false`、`fingerprint=null`、`permissionResult=blocked-missing-credential`。 - 因 credential material 缺失,未执行权限 API 探测;不得声称 Contents、Metadata 或 Webhooks 权限已实际授予。 diff --git a/scripts/src/platform-infra-gitea-config.test.ts b/scripts/src/platform-infra-gitea-config.test.ts index df7b4dd3..e141026d 100644 --- a/scripts/src/platform-infra-gitea-config.test.ts +++ b/scripts/src/platform-infra-gitea-config.test.ts @@ -83,4 +83,59 @@ describe("platform-infra Gitea repository GitHub credentials", () => { expect(stdout).not.toContain('"stack"'); expect(result.stderr.toString()).not.toContain("platform-infra-gitea.ts:"); }); + + test("renders missing selfmedia webhook status as compact text by default", () => { + const result = Bun.spawnSync({ + cmd: [ + "bun", + "scripts/cli.ts", + "platform-infra", + "gitea", + "mirror", + "webhook", + "status", + "--target", + "NC01", + "--repo", + "selfmedia-nc01", + ], + stdout: "pipe", + stderr: "pipe", + }); + const stdout = result.stdout.toString(); + + expect(stdout).toContain("PLATFORM-INFRA GITEA MIRROR WEBHOOK STATUS"); + expect(stdout).toContain("SOURCE_REF"); + expect(stdout).toContain("pikainc-selfmedia-gh-token.txt"); + expect(stdout).toContain("PERMISSION_RESULT"); + expect(stdout).toContain("github-upstream:selfmedia-nc01"); + expect(stdout.trimStart()).not.toStartWith("{"); + expect(stdout).not.toContain('"stack"'); + expect(result.stderr.toString()).not.toContain("platform-infra-gitea.ts:"); + }); + + test("matches compact blocker rows to their repository without --repo", () => { + const result = Bun.spawnSync({ + cmd: [ + "bun", + "scripts/cli.ts", + "platform-infra", + "gitea", + "mirror", + "webhook", + "status", + "--target", + "NC01", + ], + stdout: "pipe", + stderr: "pipe", + }); + const stdout = result.stdout.toString(); + + expect(stdout).toContain("pikainc/selfmedia"); + expect(stdout).toContain("pikainc-selfmedia-gh-token.txt"); + expect(stdout).toContain("github-upstream:selfmedia-nc01"); + expect(stdout).not.toContain("pikasTech/agentrun"); + expect(stdout.trimStart()).not.toStartWith("{"); + }); }); diff --git a/scripts/src/platform-infra-gitea-render.ts b/scripts/src/platform-infra-gitea-render.ts index 73271297..71d02822 100644 --- a/scripts/src/platform-infra-gitea-render.ts +++ b/scripts/src/platform-infra-gitea-render.ts @@ -107,6 +107,44 @@ export function renderMirrorWebhookApply(result: Record): Rende ]); } +export function renderMirrorWebhookCredentialBlocked(result: Record): RenderedCliResult { + const target = record(result.target); + const error = record(result.error); + const blockerIds = Array.isArray(error.blockers) ? error.blockers.map(String) : []; + const repositories = arrayRecords(result.repositories); + const credentials = arrayRecords(result.credentials); + const rows = blockerIds.map((blocker) => { + const credential = credentials.find((item) => stringValue(item.id) === blocker) ?? {}; + const permissionResult = record(credential.permissionResult); + const permissions = record(permissionResult.permissions); + const repoKey = blocker.includes(":") ? blocker.slice(blocker.indexOf(":") + 1) : ""; + const repository = repositories.find((item) => stringValue(item.key) === repoKey) ?? {}; + const permissionText = [ + `status=${stringValue(permissionResult.status)}`, + `contents=${stringValue(permissions.contents)}`, + `metadata=${stringValue(permissions.metadata)}`, + `webhooks=${stringValue(permissions.webhooks)}`, + ].join(","); + return [ + stringValue(target.id), + stringValue(credential.repository, stringValue(repository.upstreamRepository)), + stringValue(credential.sourceRef), + boolText(credential.present), + stringValue(credential.fingerprint), + permissionText, + blocker, + boolText(credential.valuesPrinted), + ]; + }); + const next = record(result.next); + return rendered(result, "platform-infra gitea mirror webhook status", [ + "PLATFORM-INFRA GITEA MIRROR WEBHOOK STATUS", + ...(rows.length === 0 ? ["-"] : table(["TARGET", "REPOSITORY", "SOURCE_REF", "PRESENT", "FINGERPRINT", "PERMISSION_RESULT", "BLOCKER", "VALUES_PRINTED"], rows)), + "", + `NEXT ${stringValue(next.webhookStatusFull)}`, + ]); +} + export function renderMirrorWebhookStatus(result: Record, disclosure: Record): RenderedCliResult { const repos = arrayRecords(result.repositories).map((repo) => { const delivery = record(repo.selectedPushDelivery); diff --git a/scripts/src/platform-infra-gitea.ts b/scripts/src/platform-infra-gitea.ts index b6cab6fa..03606bc9 100644 --- a/scripts/src/platform-infra-gitea.ts +++ b/scripts/src/platform-infra-gitea.ts @@ -30,6 +30,7 @@ import { renderMirrorStatus, renderMirrorSync, renderMirrorWebhookApply, + renderMirrorWebhookCredentialBlocked, renderMirrorWebhookStatus, renderPlan, renderStatus, @@ -298,7 +299,7 @@ async function mirrorWebhookCommand(config: UniDeskConfig, args: string[]): Prom if (action === "status") { const options = parseMirrorWebhookStatusOptions(args.slice(1)); const result = await mirrorWebhookStatus(config, options); - if (result.credentialBlocked === true) return result; + if (result.credentialBlocked === true) return options.full || options.raw ? result : renderMirrorWebhookCredentialBlocked(result); if (options.raw) return rawMirrorWebhookStatus(result); const disclosure = buildMirrorWebhookStatusDisclosure(result, options); return options.full ? disclosure : renderMirrorWebhookStatus(result, disclosure);