test: isolate repository credential status fixtures

This commit is contained in:
Codex
2026-07-13 13:40:18 +02:00
parent ac67ea5ca4
commit c04e23a355
3 changed files with 73 additions and 85 deletions
@@ -32,12 +32,12 @@
- `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 NC01 --repo selfmedia-nc01 --dry-run --full``OK=true``blockers=[]`;全局与 repository override 均只显示脱敏 presence/fingerprint,不显示 token
- `mirror webhook status --target NC01 --repo selfmedia-nc01 --full`可读取私有仓库 HEAD `6e6a95297c3c153ab269410a079a997adc345774`;当前 `hookReady=false``driftTypes=[desired-url-missing]`、有界错误为 `github-hook-missing`
- 三个 missing-credential 回归改用 synthetic blocker 输入,不再 spawn 宿主 CLI、不读取 sourceRef、不接触或打印 tokencompact/full 合同仍覆盖
- `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 权限已实际授予
- 专用凭据只读状态:`sourceRef=pikainc-selfmedia-gh-token.txt``presence=true``mode=600``fingerprint=sha256:5eed1c04a44ac5e4``valuesPrinted=false`
- 受控 status 已验证私有 HEAD 与 hooks list 可读,但未创建 hook;不得把可读性推断为超出 YAML 声明的额外权限,也不得披露 token 值
## 并行保护
@@ -62,5 +62,5 @@
## 当前结论
- R1.1 配置、schema、renderer、Secret、bridge、observer 与受控 fetch 的源码能力已落地并通过轻量验证。
- 外部 credential material 仍缺失R1.1 保持 `in_progress`
- 凭据到位后的下一步仅允许通过受控 CLI 观察脱敏 permissionResult、hook reconciler 与自动交付收敛,不得以手工触发替代自动链路
- repository-scoped credential material 已到位且 mode 为 `0600`;当前 GitHub hook 尚未创建R1.1 保持 `in_progress`
- 下一步仅允许在授权的自动控制面中观察 hook reconciler 与自动交付收敛;本次未执行 hook 创建、Secret sync、apply、bootstrap 或任何部署
+44 -64
View File
@@ -4,7 +4,34 @@ import {
readGiteaConfig,
resolveTarget,
} from "./platform-infra-gitea-config";
import { renderManifest } from "./platform-infra-gitea";
import { buildMirrorWebhookCredentialBlockedResult, renderManifest } from "./platform-infra-gitea";
import { renderMirrorWebhookCredentialBlocked } from "./platform-infra-gitea-render";
function syntheticMissingSelfmediaCredential(): Record<string, unknown> {
return {
id: "github-upstream:selfmedia-nc01",
repository: "pikainc/selfmedia",
sourceRef: "pikainc-selfmedia-gh-token.txt",
present: false,
requiredKeysPresent: false,
fingerprint: null,
permissionResult: {
status: "blocked-missing-credential",
permissions: { contents: "read", metadata: "read", webhooks: "read-write" },
error: "credential material is absent",
},
valuesPrinted: false,
};
}
function syntheticBlockedResult(allTargetRepositories = false): Record<string, unknown> {
const config = readGiteaConfig();
const target = resolveTarget(config, "NC01");
const repositories = config.sourceAuthority.repositories.filter((repo) => repo.targetId === "NC01"
&& (allTargetRepositories || repo.key === "selfmedia-nc01"));
const credential = syntheticMissingSelfmediaCredential();
return buildMirrorWebhookCredentialBlockedResult(config, target, repositories, [credential], [String(credential.id)]);
}
describe("platform-infra Gitea repository GitHub credentials", () => {
test("keeps the global credential and selfmedia override on distinct Secret keys", () => {
@@ -40,39 +67,25 @@ describe("platform-infra Gitea repository GitHub credentials", () => {
test("does not inject the NC01 selfmedia token into JD01 bridge containers", () => {
const config = readGiteaConfig();
const tokenEnv = githubTokenEnvNameForSecretKey("github-token-pikainc-selfmedia");
const selfmediaTokenEnv = githubTokenEnvNameForSecretKey("github-token-pikainc-selfmedia");
const globalTokenEnv = githubTokenEnvNameForSecretKey(config.sourceAuthority.credentials.github.gitFetchCredential.secretRef.key);
const jd01Manifest = renderManifest(config, resolveTarget(config, "JD01"));
const nc01Manifest = renderManifest(config, resolveTarget(config, "NC01"));
expect(jd01Manifest).not.toContain(tokenEnv);
expect(nc01Manifest).toContain(tokenEnv);
expect(jd01Manifest).toContain(globalTokenEnv);
expect(jd01Manifest).not.toContain(selfmediaTokenEnv);
expect(nc01Manifest).toContain(globalTokenEnv);
expect(nc01Manifest).toContain(selfmediaTokenEnv);
expect(nc01Manifest).toContain(`"tokenEnv": "${selfmediaTokenEnv}"`);
});
test("keeps missing selfmedia webhook status bounded and stack-free", () => {
const result = Bun.spawnSync({
cmd: [
"bun",
"scripts/cli.ts",
"platform-infra",
"gitea",
"mirror",
"webhook",
"status",
"--target",
"NC01",
"--repo",
"selfmedia-nc01",
"--full",
],
stdout: "pipe",
stderr: "pipe",
});
const stdout = result.stdout.toString();
const payload = JSON.parse(stdout);
const credentials = payload.data.credentials as Array<Record<string, unknown>>;
const selfmedia = credentials.find((item) => item.id === "github-upstream:selfmedia-nc01");
const payload = syntheticBlockedResult();
const credentials = payload.credentials as Array<Record<string, unknown>>;
const selfmedia = credentials[0];
const serialized = JSON.stringify(payload);
expect(payload.data.error.code).toBe("github-credential-unavailable");
expect((payload.error as Record<string, unknown>).code).toBe("github-credential-unavailable");
expect(selfmedia).toMatchObject({
sourceRef: "pikainc-selfmedia-gh-token.txt",
present: false,
@@ -80,29 +93,12 @@ describe("platform-infra Gitea repository GitHub credentials", () => {
valuesPrinted: false,
});
expect(selfmedia).not.toHaveProperty("sourcePath");
expect(stdout).not.toContain('"stack"');
expect(result.stderr.toString()).not.toContain("platform-infra-gitea.ts:");
expect(serialized).not.toContain('"stack"');
expect(serialized).not.toContain("/root/.worktrees/");
});
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();
const stdout = renderMirrorWebhookCredentialBlocked(syntheticBlockedResult()).renderedText;
expect(stdout).toContain("PLATFORM-INFRA GITEA MIRROR WEBHOOK STATUS");
expect(stdout).toContain("SOURCE_REF");
@@ -111,26 +107,10 @@ describe("platform-infra Gitea repository GitHub credentials", () => {
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();
const stdout = renderMirrorWebhookCredentialBlocked(syntheticBlockedResult(true)).renderedText;
expect(stdout).toContain("pikainc/selfmedia");
expect(stdout).toContain("pikainc-selfmedia-gh-token.txt");
+22 -14
View File
@@ -475,20 +475,7 @@ async function mirrorWebhookStatus(config: UniDeskConfig, options: MirrorWebhook
const repos = selectedRepositories(gitea, target, options.repoKey);
const credentials = credentialSummaries(gitea, repos);
const blockers = credentialBlockers(credentials);
if (blockers.length > 0) {
return {
ok: false,
action: "platform-infra-gitea-mirror-webhook-status",
mutation: false,
credentialBlocked: true,
target: targetSummary(target),
webhook: webhookSyncSummary(gitea, target),
repositories: repos.map((repo) => repositorySummary(gitea, repo)),
credentials,
error: { code: "github-credential-unavailable", blockers, valuesPrinted: false },
next: mirrorReadOnlyNextCommands(target.id),
};
}
if (blockers.length > 0) return buildMirrorWebhookCredentialBlockedResult(gitea, target, repos, credentials, blockers);
const secrets = ensureMirrorSecrets(gitea, target, repos, false, false, false);
const result = await capture(config, target.route, ["sh"], remoteScript("mirror-webhook-status", gitea, target, "", { ...options, confirm: false, dryRun: true, wait: false }, { repos, secrets }).script);
const parsed = parseJsonOutput(result.stdout);
@@ -508,6 +495,27 @@ async function mirrorWebhookStatus(config: UniDeskConfig, options: MirrorWebhook
};
}
export function buildMirrorWebhookCredentialBlockedResult(
gitea: GiteaConfig,
target: GiteaTarget,
repos: GiteaMirrorRepository[],
credentials: Array<Record<string, unknown>>,
blockers: string[],
): Record<string, unknown> {
return {
ok: false,
action: "platform-infra-gitea-mirror-webhook-status",
mutation: false,
credentialBlocked: true,
target: targetSummary(target),
webhook: webhookSyncSummary(gitea, target),
repositories: repos.map((repo) => repositorySummary(gitea, repo)),
credentials,
error: { code: "github-credential-unavailable", blockers, valuesPrinted: false },
next: mirrorReadOnlyNextCommands(target.id),
};
}
export function renderManifest(gitea: GiteaConfig, target: GiteaTarget): string {
const app = gitea.app;
const image = `${app.image.repository}:${app.image.tag}`;