Files
pikasTech-unidesk/scripts/src/agentrun-managed-repository-reconciler.test.ts
T

719 lines
32 KiB
TypeScript

import { createHash } from "node:crypto";
import {
chmodSync,
copyFileSync,
existsSync,
mkdirSync,
mkdtempSync,
readFileSync,
rmSync,
writeFileSync,
} from "node:fs";
import { join } from "node:path";
import { describe, expect, test } from "bun:test";
import {
agentRunManagedRepositoryDesiredConfig,
agentRunManagedRepositoryRenderHash,
renderAgentRunManagedRepositoryReconcilerFragment,
} from "./agentrun-managed-repository-reconciler";
import {
parseAgentRunGitFetchCredentialCapability,
resolveAgentRunLaneTarget,
} from "./agentrun-lanes";
import { resolveCicdDeliveryAuthority } from "./cicd-delivery-authority";
import { renderGitMirrorStatusEnvelope } from "./agentrun/git-mirror";
import { yamlLaneGitMirrorStatusScript } from "./agentrun/secrets";
import { renderPlatformInfraGiteaDesiredFragments } from "./platform-infra-gitea-desired-fragments";
const controllerPath = new URL("../native/agentrun/managed-repository-reconciler.mjs", import.meta.url).pathname;
const askPassPath = new URL("../native/agentrun/git-askpass.mjs", import.meta.url).pathname;
describe("AgentRun YAML-owned managed repository reconciler", () => {
test("renders one narrow controller from the lane repository list", () => {
const spec = resolveAgentRunLaneTarget({ node: "NC01", lane: "nc01-v02" }).spec;
const desired = agentRunManagedRepositoryDesiredConfig(spec);
expect(desired.repositories.map((item) => item.repository)).toEqual([
"pikasTech/agentrun",
"pikasTech/unidesk",
"pikasTech/agent_skills",
]);
expect(desired.repositories.every((item) => item.remote.startsWith("https://github.com/"))).toBe(true);
expect(desired.remoteAuth).toMatchObject({
authMode: "github-https-token",
host: "github.com",
proxy: { host: "127.0.0.1", port: 10808 },
});
expect(desired.lifecycle).toEqual({
undeclaredRepositoryPolicy: "retain",
managedRefs: "source-branch-only",
});
const documents = renderAgentRunManagedRepositoryReconcilerFragment("NC01")
.split(/^---\s*$/mu)
.map((item) => Bun.YAML.parse(item) as any);
expect(documents.map((item) => item.kind)).toEqual(["ServiceAccount", "ConfigMap", "Deployment"]);
expect(documents[0].automountServiceAccountToken).toBe(false);
expect(documents[1].metadata.annotations["unidesk.ai/undeclared-repository-policy"]).toBe("retain");
expect(JSON.parse(documents[1].data["config.json"]).repositories).toEqual(desired.repositories);
expect(documents[2].spec.strategy.type).toBe("Recreate");
expect(documents[2].spec.template.spec.automountServiceAccountToken).toBe(false);
expect(documents[2].spec.template.spec.hostNetwork).toBe(spec.gitMirror.repositoryReconciler.hostNetwork);
expect(documents[2].spec.template.spec.dnsPolicy).toBe(spec.gitMirror.repositoryReconciler.dnsPolicy);
expect(documents[2].spec.template.spec.containers[0].readinessProbe.exec.command).toContain("--health");
const authVolume = documents[2].spec.template.spec.volumes.find((item: any) => item.name === "git-auth");
expect(authVolume.projected.sources).toHaveLength(2);
expect(authVolume.projected.sources[1].secret).toEqual({
name: "gitea-github-sync-secrets",
items: [{ key: "github-token", path: "token", mode: 256 }],
});
expect(JSON.stringify(authVolume)).not.toContain("gitea-username");
expect(JSON.stringify(authVolume)).not.toContain("gitea-password");
expect(JSON.stringify(authVolume)).not.toContain("github-webhook-secret");
expect(documents[2].spec.template.spec.volumes.some((item: any) => item.name === "git-ssh")).toBe(false);
expect(renderAgentRunManagedRepositoryReconcilerFragment("JD01")).toBe("");
const controllerSource = readFileSync(controllerPath, "utf8");
expect(controllerSource).not.toContain("agent_skills");
expect(controllerSource).not.toContain("pikasTech/");
expect(controllerSource).not.toContain("github.com");
});
test("registers after PaC-owned admission objects without identity or separator conflicts", () => {
const spec = resolveAgentRunLaneTarget({ node: "NC01", lane: "nc01-v02" }).spec;
const desired = agentRunManagedRepositoryDesiredConfig(spec);
const fragment = renderPlatformInfraGiteaDesiredFragments("NC01");
expect(fragment).not.toContain("---\n---");
const documents = fragment
.split(/^---\s*$/mu)
.map((item) => Bun.YAML.parse(item) as any);
expect(documents.map((item) => item.kind)).toEqual([
"Role",
"RoleBinding",
"ValidatingAdmissionPolicy",
"ValidatingAdmissionPolicyBinding",
"ServiceAccount",
"ConfigMap",
"Deployment",
]);
const identities = documents.map((item) => [
item.apiVersion,
item.kind,
item.metadata.namespace ?? "_cluster",
item.metadata.name,
].join("/"));
expect(new Set(identities).size).toBe(documents.length);
const managed = documents.slice(-3);
expect(managed.map((item) => item.metadata.name)).toEqual([
spec.gitMirror.repositoryReconciler.serviceAccountName,
spec.gitMirror.repositoryReconciler.configMapName,
spec.gitMirror.repositoryReconciler.deploymentName,
]);
const config = JSON.parse(managed[1].data["config.json"]);
expect(config.desiredHash).toBe(desired.desiredHash);
expect(managed[1].metadata.annotations["unidesk.ai/managed-repository-desired-sha"]).toBe(desired.desiredHash);
expect(managed[2].metadata.annotations["unidesk.ai/managed-repository-desired-sha"]).toBe(desired.desiredHash);
expect(managed[1].metadata.annotations["unidesk.ai/managed-repository-render-sha"]).toMatch(/^[0-9a-f]{64}$/u);
expect(managed[2].metadata.annotations["unidesk.ai/managed-repository-render-sha"]).toBe(
managed[1].metadata.annotations["unidesk.ai/managed-repository-render-sha"],
);
});
test("requires every repository entry to own a matching remote", () => {
const temporary = mkdtempSync("/tmp/unidesk-agentrun-repository-config-");
try {
const source = readFileSync(new URL("../../config/agentrun.yaml", import.meta.url), "utf8");
const invalid = source.replace(
"remote: https://github.com/pikasTech/agent_skills.git",
"remote: https://github.com/pikasTech/unidesk.git",
);
const configPath = join(temporary, "agentrun.yaml");
writeFileSync(configPath, invalid);
expect(() => resolveAgentRunLaneTarget(
{ node: "NC01", lane: "nc01-v02" },
{ ...process.env, AGENTRUN_CONTROL_PLANE_CONFIG: configPath },
)).toThrow("same repository entry");
} finally {
rmSync(temporary, { recursive: true, force: true });
}
});
test("fails closed on non-canonical remotes and malformed credential capabilities", () => {
const source = readFileSync(new URL("../../config/agentrun.yaml", import.meta.url), "utf8");
const canonical = "https://github.com/pikasTech/agent_skills.git";
const invalidRemotes = [
"ssh://git@ssh.github.com:443/pikasTech/agent_skills.git",
"https://user@github.com/pikasTech/agent_skills.git",
"https://github.com:443/pikasTech/agent_skills.git",
"https://github.com/pikasTech/agent_skills.git?token=forbidden",
"https://github.com/pikasTech/agent_skills.git#forbidden",
"https://example.com/pikasTech/agent_skills.git",
"https://github.com/pikasTech/unidesk.git",
];
const temporary = mkdtempSync("/tmp/unidesk-agentrun-remote-contract-");
try {
for (const [index, remote] of invalidRemotes.entries()) {
const configPath = join(temporary, `invalid-${index}.yaml`);
writeFileSync(configPath, source.replace(`remote: ${canonical}`, `remote: ${remote}`));
expect(() => resolveAgentRunLaneTarget(
{ node: "NC01", lane: "nc01-v02" },
{ ...process.env, AGENTRUN_CONTROL_PLANE_CONFIG: configPath },
)).toThrow();
}
} finally {
rmSync(temporary, { recursive: true, force: true });
}
const validCapability = {
apiVersion: "unidesk.ai/v1",
kind: "GitFetchCredential",
authMode: "github-https-token",
host: "github.com",
secretRef: { namespace: "devops-infra", name: "gitea-github-sync-secrets", key: "github-token" },
};
expect(parseAgentRunGitFetchCredentialCapability(validCapability)).toEqual(validCapability);
for (const invalid of [
{ ...validCapability, kind: "Secret" },
{ ...validCapability, authMode: "ssh" },
{ ...validCapability, host: "example.com" },
{ ...validCapability, secretRef: { ...validCapability.secretRef, key: "invalid/key" } },
]) expect(() => parseAgentRunGitFetchCredentialCapability(invalid)).toThrow();
});
test("renders host networking only from the explicit reconciler fields", () => {
const temporary = mkdtempSync("/tmp/unidesk-agentrun-repository-network-");
try {
const source = readFileSync(new URL("../../config/agentrun.yaml", import.meta.url), "utf8");
const nonLoopbackProxy = source.replace(
"githubProxy:\n host: 127.0.0.1\n port: 10808",
"githubProxy:\n host: proxy.internal.example\n port: 10808",
);
const nonLoopbackPath = join(temporary, "non-loopback.yaml");
writeFileSync(nonLoopbackPath, nonLoopbackProxy);
const nonLoopbackEnv = { ...process.env, AGENTRUN_CONTROL_PLANE_CONFIG: nonLoopbackPath };
const nonLoopbackDeployment = renderAgentRunManagedRepositoryReconcilerFragment("NC01", nonLoopbackEnv)
.split(/^---\s*$/mu)
.map((item) => Bun.YAML.parse(item) as any)
.find((item) => item.kind === "Deployment");
expect(nonLoopbackDeployment.spec.template.spec.hostNetwork).toBe(true);
expect(nonLoopbackDeployment.spec.template.spec.dnsPolicy).toBe("ClusterFirstWithHostNet");
const clusterNetwork = source.replace(
"hostNetwork: true\n dnsPolicy: ClusterFirstWithHostNet",
"hostNetwork: false\n dnsPolicy: ClusterFirst",
);
const clusterNetworkPath = join(temporary, "cluster-network.yaml");
writeFileSync(clusterNetworkPath, clusterNetwork);
const clusterNetworkEnv = { ...process.env, AGENTRUN_CONTROL_PLANE_CONFIG: clusterNetworkPath };
const clusterNetworkSpec = resolveAgentRunLaneTarget(
{ node: "NC01", lane: "nc01-v02" },
clusterNetworkEnv,
).spec;
const clusterNetworkDeployment = renderAgentRunManagedRepositoryReconcilerFragment("NC01", clusterNetworkEnv)
.split(/^---\s*$/mu)
.map((item) => Bun.YAML.parse(item) as any)
.find((item) => item.kind === "Deployment");
expect(clusterNetworkDeployment.spec.template.spec.hostNetwork).toBe(false);
expect(clusterNetworkDeployment.spec.template.spec.dnsPolicy).toBe("ClusterFirst");
const defaultSpec = resolveAgentRunLaneTarget({ node: "NC01", lane: "nc01-v02" }).spec;
expect(agentRunManagedRepositoryRenderHash(clusterNetworkSpec)).not.toBe(agentRunManagedRepositoryRenderHash(defaultSpec));
const invalidHostNetworkPath = join(temporary, "invalid-host-network.yaml");
writeFileSync(invalidHostNetworkPath, source.replace("dnsPolicy: ClusterFirstWithHostNet", "dnsPolicy: ClusterFirst"));
expect(() => resolveAgentRunLaneTarget(
{ node: "NC01", lane: "nc01-v02" },
{ ...process.env, AGENTRUN_CONTROL_PLANE_CONFIG: invalidHostNetworkPath },
)).toThrow("must be ClusterFirstWithHostNet when");
const invalidClusterNetworkPath = join(temporary, "invalid-cluster-network.yaml");
writeFileSync(invalidClusterNetworkPath, source.replace("hostNetwork: true", "hostNetwork: false"));
expect(() => resolveAgentRunLaneTarget(
{ node: "NC01", lane: "nc01-v02" },
{ ...process.env, AGENTRUN_CONTROL_PLANE_CONFIG: invalidClusterNetworkPath },
)).toThrow("must not be ClusterFirstWithHostNet when");
} finally {
rmSync(temporary, { recursive: true, force: true });
}
});
test("materializes source refs, exposes health, and retains undeclared cache content", () => {
const temporary = mkdtempSync("/tmp/unidesk-agentrun-managed-repository-");
try {
const work = join(temporary, "work");
const remote = join(temporary, "remote.git");
const cache = join(temporary, "cache");
const auth = join(temporary, "auth");
const fakeBin = join(temporary, "bin");
const gitObservationPath = join(temporary, "git-observations.jsonl");
const tokenPath = join(auth, "token");
const fixtureAskPassPath = join(auth, "git-askpass.mjs");
mkdirSync(work, { recursive: true });
mkdirSync(cache, { recursive: true });
mkdirSync(auth, { recursive: true });
mkdirSync(fakeBin, { recursive: true });
git(["init", work]);
git(["-C", work, "config", "user.name", "UniDesk fixture"]);
git(["-C", work, "config", "user.email", "fixture@unidesk.invalid"]);
writeFileSync(join(work, "README.md"), "managed repository fixture\n");
git(["-C", work, "add", "README.md"]);
git(["-C", work, "commit", "-m", "fixture"]);
git(["-C", work, "branch", "-M", "main"]);
git(["clone", "--bare", work, remote]);
const fixtureToken = "github_pat_fixture_not_for_logs";
writeFileSync(tokenPath, `${fixtureToken}\n`);
copyFileSync(askPassPath, fixtureAskPassPath);
chmodSync(fixtureAskPassPath, 0o555);
const retainedPath = join(cache, "undeclared", "retained.git");
mkdirSync(retainedPath, { recursive: true });
writeFileSync(join(retainedPath, "marker"), "retain\n");
const remoteUrl = "https://github.com/acme/example.git";
writeGitShim({
path: join(fakeBin, "git"),
realGit: Bun.which("git")!,
observationPath: gitObservationPath,
remoteUrl,
replacementRemoteUrl: `file://${remote}`,
});
const repository = {
key: "fixture",
repository: "acme/example",
remote: remoteUrl,
sourceBranch: "main",
desiredFingerprint: sha256(["fixture", "acme/example", remoteUrl, "main"].join("\0")),
};
const desired = {
schemaVersion: 1,
kind: "AgentRunManagedRepositoryReconciler",
nodeId: "fixture-node",
lane: "fixture-lane",
cacheMountPath: cache,
stateDirectory: ".managed-state",
reconcileIntervalMs: 1000,
fetchTimeoutMs: 10000,
shutdownGraceMs: 1000,
maxConcurrentRepositories: 1,
retry: { maxAttempts: 1, initialDelayMs: 10, maxDelayMs: 10 },
freshness: { maxAgeMs: 60000 },
lifecycle: { undeclaredRepositoryPolicy: "retain", managedRefs: "source-branch-only" },
repositories: [repository],
remoteAuth: {
configRef: "config/platform-infra/gitea.yaml#sourceAuthority.credentials.github.gitFetchCredential",
capabilitySha256: "a".repeat(64),
authMode: "github-https-token",
host: "github.com",
tokenFile: tokenPath,
askPassFile: fixtureAskPassPath,
proxy: { host: "127.0.0.1", port: 10808 },
},
};
const config = { ...desired, desiredHash: sha256(JSON.stringify(desired)) };
const configPath = join(temporary, "config.json");
writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
const once = Bun.spawnSync(["node", controllerPath, "--once", "--config", configPath], {
stdout: "pipe",
stderr: "pipe",
env: inheritedHostileGitEnvironment(fakeBin, fixtureToken),
});
expect(once.exitCode, once.stderr.toString()).toBe(0);
expect(`${once.stdout.toString()}\n${once.stderr.toString()}`).not.toContain(fixtureToken);
const onceStatus = JSON.parse(once.stdout.toString());
expect(onceStatus.ready).toBe(true);
expect(onceStatus.repositories[0].remoteFingerprint).toBe(`sha256:${sha256(remoteUrl)}`);
expect(existsSync(join(retainedPath, "marker"))).toBe(true);
const gitObservations = readFileSync(gitObservationPath, "utf8")
.trim()
.split("\n")
.map((line) => JSON.parse(line));
expect(gitObservations.some((item) => item.args.includes(remoteUrl))).toBe(true);
expect(gitObservations.every((item) => item.inheritedGitSsh === false)).toBe(true);
expect(gitObservations.every((item) => item.inheritedGitConfig === false)).toBe(true);
expect(gitObservations.every((item) => item.inheritedGithubToken === false)).toBe(true);
expect(gitObservations.every((item) => item.askPassConfigured === true)).toBe(true);
expect(gitObservations.every((item) => item.tlsVerifyForced === true)).toBe(true);
expect(readFileSync(gitObservationPath, "utf8")).not.toContain(fixtureToken);
const mirroredCommit = git([
"--git-dir",
join(cache, "acme", "example.git"),
"rev-parse",
"--verify",
"refs/heads/main^{commit}",
]).trim();
expect(mirroredCommit).toMatch(/^[0-9a-f]{40}$/u);
expect(readFileSync(join(cache, "acme", "example.git", "config"), "utf8")).not.toContain(fixtureToken);
expect(readFileSync(join(cache, ".managed-state", "status.json"), "utf8")).not.toContain(fixtureToken);
git([
"--git-dir",
join(cache, "acme", "example.git"),
"update-ref",
"refs/heads/retained-gitops",
mirroredCommit,
]);
const secondOnce = Bun.spawnSync(["node", controllerPath, "--once", "--config", configPath], {
stdout: "pipe",
stderr: "pipe",
env: inheritedHostileGitEnvironment(fakeBin, fixtureToken),
});
expect(secondOnce.exitCode, secondOnce.stderr.toString()).toBe(0);
expect(git([
"--git-dir",
join(cache, "acme", "example.git"),
"rev-parse",
"--verify",
"refs/heads/retained-gitops^{commit}",
])).toBe(mirroredCommit);
expect(git([
"--git-dir",
join(cache, "acme", "example.git"),
"for-each-ref",
"--format=%(refname)",
"refs/agentrun-managed",
])).toBe("");
const health = Bun.spawnSync(["node", controllerPath, "--health", "--config", configPath], {
stdout: "pipe",
stderr: "pipe",
env: inheritedHostileGitEnvironment(fakeBin, fixtureToken),
});
expect(health.exitCode, health.stderr.toString()).toBe(0);
const healthStatus = JSON.parse(health.stdout.toString());
expect(healthStatus.ready).toBe(true);
expect(healthStatus.repositories[0]).toMatchObject({
refPresent: true,
fresh: true,
commit: mirroredCommit,
remoteFingerprintAligned: true,
});
} finally {
rmSync(temporary, { recursive: true, force: true });
}
});
test("keeps readiness false and skips Git when the projected credential is missing or empty", () => {
const temporary = mkdtempSync("/tmp/unidesk-agentrun-managed-repository-credential-");
try {
const cache = join(temporary, "cache");
const auth = join(temporary, "auth");
const fakeBin = join(temporary, "bin");
const gitMarker = join(temporary, "git-invoked");
const tokenPath = join(auth, "token");
const fixtureAskPassPath = join(auth, "git-askpass.mjs");
mkdirSync(cache, { recursive: true });
mkdirSync(auth, { recursive: true });
mkdirSync(fakeBin, { recursive: true });
copyFileSync(askPassPath, fixtureAskPassPath);
chmodSync(fixtureAskPassPath, 0o555);
writeFileSync(join(fakeBin, "git"), `#!/bin/sh\ntouch ${JSON.stringify(gitMarker)}\nexit 99\n`);
chmodSync(join(fakeBin, "git"), 0o755);
const configPath = join(temporary, "config.json");
writeControllerConfig(configPath, { cache, tokenPath, askPassFile: fixtureAskPassPath });
writeFileSync(tokenPath, "\n");
const empty = Bun.spawnSync(["node", controllerPath, "--once", "--config", configPath], {
stdout: "pipe",
stderr: "pipe",
env: inheritedHostileGitEnvironment(fakeBin, "inherited-token-must-not-leak"),
});
expect(empty.exitCode).toBe(1);
const emptyStatus = lastJsonLine(empty.stdout.toString());
expect(emptyStatus).toMatchObject({
ready: false,
credential: { ready: false, errorCode: "credential-empty", valuesPrinted: false },
repositories: [{ lastAttemptOk: false, errorCode: "credential-empty" }],
valuesPrinted: false,
});
expect(existsSync(gitMarker)).toBe(false);
rmSync(tokenPath);
const missing = Bun.spawnSync(["node", controllerPath, "--health", "--config", configPath], {
stdout: "pipe",
stderr: "pipe",
env: inheritedHostileGitEnvironment(fakeBin, "inherited-token-must-not-leak"),
});
expect(missing.exitCode).toBe(1);
expect(JSON.parse(missing.stdout.toString())).toMatchObject({
ready: false,
credential: { ready: false, errorCode: "credential-file-missing", valuesPrinted: false },
valuesPrinted: false,
});
expect(existsSync(gitMarker)).toBe(false);
} finally {
rmSync(temporary, { recursive: true, force: true });
}
});
test("redacts authentication failures from logs, status, and repository config", () => {
const temporary = mkdtempSync("/tmp/unidesk-agentrun-managed-repository-redaction-");
try {
const work = join(temporary, "work");
const remote = join(temporary, "remote.git");
const cache = join(temporary, "cache");
const auth = join(temporary, "auth");
const fakeBin = join(temporary, "bin");
const tokenPath = join(auth, "token");
const fixtureAskPassPath = join(auth, "git-askpass.mjs");
const gitObservationPath = join(temporary, "git-observations.jsonl");
const remoteUrl = "https://github.com/acme/example.git";
const sensitive = "github_pat_sensitive_authentication_failure";
mkdirSync(work, { recursive: true });
mkdirSync(cache, { recursive: true });
mkdirSync(auth, { recursive: true });
mkdirSync(fakeBin, { recursive: true });
git(["init", work]);
git(["clone", "--bare", work, remote]);
writeFileSync(tokenPath, `${sensitive}\n`);
copyFileSync(askPassPath, fixtureAskPassPath);
chmodSync(fixtureAskPassPath, 0o555);
writeGitShim({
path: join(fakeBin, "git"),
realGit: Bun.which("git")!,
observationPath: gitObservationPath,
remoteUrl,
replacementRemoteUrl: `file://${remote}`,
failFetchMessage: `authentication failed for ${sensitive}`,
});
const configPath = join(temporary, "config.json");
writeControllerConfig(configPath, { cache, tokenPath, askPassFile: fixtureAskPassPath });
const once = Bun.spawnSync(["node", controllerPath, "--once", "--config", configPath], {
stdout: "pipe",
stderr: "pipe",
env: inheritedHostileGitEnvironment(fakeBin, sensitive),
});
expect(once.exitCode).toBe(1);
const combined = `${once.stdout.toString()}\n${once.stderr.toString()}`;
expect(combined).not.toContain(sensitive);
const status = lastJsonLine(once.stdout.toString());
expect(status.repositories[0]).toMatchObject({
lastAttemptOk: false,
errorCode: "authentication-failed",
});
expect(status.repositories[0].errorFingerprint).toMatch(/^[0-9a-f]{16}$/u);
expect(readFileSync(gitObservationPath, "utf8")).not.toContain(sensitive);
expect(readFileSync(join(cache, ".managed-state", "status.json"), "utf8")).not.toContain(sensitive);
expect(existsSync(join(cache, "acme", "example.git"))).toBe(false);
} finally {
rmSync(temporary, { recursive: true, force: true });
}
});
test("keeps the legacy default summary contract and bounds the final CLI envelope", () => {
const target = resolveAgentRunLaneTarget({ node: "NC01", lane: "nc01-v02" });
const spec = target.spec;
const authority = resolveCicdDeliveryAuthority({
node: spec.nodeId,
lane: spec.lane,
sourceRepository: spec.source.repository,
sourceBranch: spec.source.branch,
declaredSourceAuthorityMode: spec.source.sourceAuthority?.mode ?? null,
declaredConfigRef: target.configPath,
});
expect(authority.kind).toBe("pac-pr-merge");
const defaultRepositoryLimit = spec.gitMirror.repositoryReconciler.status.defaultRepositoryLimit;
const fixtureRepositoryTotal = defaultRepositoryLimit + 2;
const repositories = Array.from({ length: fixtureRepositoryTotal }, (_, index) => ({
key: `repo-${index}`,
repository: `acme/repo-${index}`,
sourceBranch: "main",
cacheCommit: String(index).repeat(40),
cacheRefPresent: true,
servedCommit: String(index).repeat(40),
servedRefPresent: true,
refAligned: true,
remoteFingerprintAligned: true,
fresh: true,
}));
const summary = {
ok: true,
repository: "pikasTech/agentrun",
sourceBranch: "v0.2",
gitopsBranch: "nc01-v0.2-gitops",
sourceCommit: "a".repeat(40),
gitopsCommit: "b".repeat(40),
controller: {
deploymentReady: true,
configRendered: true,
workloadRendered: true,
statusAligned: true,
heartbeatFresh: true,
},
repositories,
firstDrift: null,
valuesPrinted: false,
};
const observation = {
ok: true,
summary,
raw: JSON.stringify(summary),
result: { exitCode: 0, stdout: JSON.stringify(summary), stderr: "" },
} as any;
const baseOptions = { node: "NC01", lane: "nc01-v02" };
const compact = renderGitMirrorStatusEnvelope(
target,
authority,
observation,
{ ...baseOptions, full: false, raw: false },
) as any;
expect(compact.summary).toMatchObject({
repository: "pikasTech/agentrun",
sourceBranch: "v0.2",
gitopsBranch: "nc01-v0.2-gitops",
sourceCommit: "a".repeat(40),
gitopsCommit: "b".repeat(40),
});
expect(compact.summary.repositories).toHaveLength(defaultRepositoryLimit);
expect(compact.summary.repositoryView).toEqual({
limit: defaultRepositoryLimit,
total: fixtureRepositoryTotal,
shown: defaultRepositoryLimit,
omitted: fixtureRepositoryTotal - defaultRepositoryLimit,
});
expect(compact.target.repositoryView).toEqual({
limit: defaultRepositoryLimit,
total: spec.gitMirror.repositories.length,
shown: spec.gitMirror.repositories.length,
omitted: 0,
});
expect(compact.probe.stdoutTailOmitted).toBe(true);
expect(compact.disclosure.probeTailOmitted).toBe(true);
expect(compact.next).toMatchObject({ status: expect.any(String), history: expect.any(String) });
expect(compact.next.sync).toBeUndefined();
for (const options of [
{ ...baseOptions, full: true, raw: false },
{ ...baseOptions, full: false, raw: true },
]) {
const expanded = renderGitMirrorStatusEnvelope(target, authority, observation, options) as any;
expect(expanded.summary.repositories).toHaveLength(fixtureRepositoryTotal);
expect(expanded.summary.repositoryView).toEqual({
limit: null,
total: fixtureRepositoryTotal,
shown: fixtureRepositoryTotal,
omitted: 0,
});
expect(expanded.target.repositories).toHaveLength(spec.gitMirror.repositories.length);
expect(expanded.target.repositoryView).toEqual({
limit: null,
total: spec.gitMirror.repositories.length,
shown: spec.gitMirror.repositories.length,
omitted: 0,
});
expect(expanded.probe.stdoutTailOmitted).toBe(!options.raw);
expect(expanded.probe.stdoutTail).toBe(options.raw ? JSON.stringify(summary) : undefined);
expect(expanded.disclosure.probeTailOmitted).toBe(!options.raw);
}
});
test("keeps legacy main-repository fields and bounds per-repository probes", () => {
const spec = resolveAgentRunLaneTarget({ node: "NC01", lane: "nc01-v02" }).spec;
const script = yamlLaneGitMirrorStatusScript(spec);
expect(script).toContain("'repository': os.environ.get('REPOSITORY')");
expect(script).toContain("'sourceCommit': legacy_ref(");
expect(script).toContain("'gitopsCommit': legacy_ref(");
expect(script.match(/timeout 20 kubectl/gu)?.length).toBe(spec.gitMirror.repositories.length);
expect(script.match(/timeout 20 kubectl[^\n]+ &/gu)?.length).toBe(spec.gitMirror.repositories.length);
expect(script).toContain("remoteFingerprintAligned");
});
});
function git(args: string[]): string {
const result = Bun.spawnSync(["git", ...args], { stdout: "pipe", stderr: "pipe" });
if (result.exitCode !== 0) throw new Error(`git ${args[0]} failed: ${result.stderr.toString()}`);
return result.stdout.toString().trim();
}
function sha256(value: string): string {
return createHash("sha256").update(value).digest("hex");
}
function writeControllerConfig(path: string, input: { cache: string; tokenPath: string; askPassFile: string }): void {
const remote = "https://github.com/acme/example.git";
const repository = {
key: "fixture",
repository: "acme/example",
remote,
sourceBranch: "main",
desiredFingerprint: sha256(["fixture", "acme/example", remote, "main"].join("\0")),
};
const desired = {
schemaVersion: 1,
kind: "AgentRunManagedRepositoryReconciler",
nodeId: "fixture-node",
lane: "fixture-lane",
cacheMountPath: input.cache,
stateDirectory: ".managed-state",
reconcileIntervalMs: 1000,
fetchTimeoutMs: 10000,
shutdownGraceMs: 1000,
maxConcurrentRepositories: 1,
retry: { maxAttempts: 1, initialDelayMs: 10, maxDelayMs: 10 },
freshness: { maxAgeMs: 60000 },
lifecycle: { undeclaredRepositoryPolicy: "retain", managedRefs: "source-branch-only" },
repositories: [repository],
remoteAuth: {
configRef: "config/platform-infra/gitea.yaml#sourceAuthority.credentials.github.gitFetchCredential",
capabilitySha256: "a".repeat(64),
authMode: "github-https-token",
host: "github.com",
tokenFile: input.tokenPath,
askPassFile: input.askPassFile,
proxy: { host: "127.0.0.1", port: 10808 },
},
};
writeFileSync(path, `${JSON.stringify({ ...desired, desiredHash: sha256(JSON.stringify(desired)) }, null, 2)}\n`);
}
function lastJsonLine(output: string): any {
const lines = output.trim().split("\n");
return JSON.parse(lines.at(-1) ?? "null");
}
function inheritedHostileGitEnvironment(fakeBin: string, fixtureToken: string): NodeJS.ProcessEnv {
return {
...process.env,
PATH: `${fakeBin}:${process.env.PATH ?? ""}`,
GIT_SSH: "/tmp/inherited-git-ssh",
GIT_SSH_COMMAND: "inherited-ssh-command",
GIT_CONFIG: "/tmp/inherited-git-config",
GIT_CONFIG_COUNT: "1",
GIT_CONFIG_KEY_0: "credential.helper",
GIT_CONFIG_VALUE_0: "!inherited-credential-helper",
GIT_SSL_NO_VERIFY: "1",
GH_TOKEN: fixtureToken,
GITHUB_TOKEN: fixtureToken,
};
}
function writeGitShim(input: {
path: string;
realGit: string;
observationPath: string;
remoteUrl: string;
replacementRemoteUrl: string;
failFetchMessage?: string;
}): void {
writeFileSync(input.path, `#!/usr/bin/env node
import { appendFileSync } from "node:fs";
import { spawnSync } from "node:child_process";
const args = process.argv.slice(2);
appendFileSync(${JSON.stringify(input.observationPath)}, JSON.stringify({
args,
inheritedGitSsh: Object.hasOwn(process.env, "GIT_SSH") || Object.hasOwn(process.env, "GIT_SSH_COMMAND"),
inheritedGitConfig: Object.hasOwn(process.env, "GIT_CONFIG") || Object.hasOwn(process.env, "GIT_CONFIG_COUNT") || Object.keys(process.env).some((key) => /^GIT_CONFIG_(?:KEY|VALUE)_/u.test(key)),
inheritedGithubToken: Object.hasOwn(process.env, "GH_TOKEN") || Object.hasOwn(process.env, "GITHUB_TOKEN"),
askPassConfigured: typeof process.env.GIT_ASKPASS === "string" && process.env.GIT_ASKPASS.length > 0 && process.env.GIT_ASKPASS_REQUIRE === "force",
tlsVerifyForced: process.env.GIT_SSL_NO_VERIFY === "0" && args.includes("http.sslVerify=true"),
}) + "\\n");
if (args.includes("fetch") && ${JSON.stringify(input.failFetchMessage ?? null)} !== null) {
process.stderr.write(${JSON.stringify(input.failFetchMessage ?? "")} + "\\n");
process.exit(1);
}
const mapped = args.map((arg) => arg === ${JSON.stringify(input.remoteUrl)} ? ${JSON.stringify(input.replacementRemoteUrl)} : arg);
const result = spawnSync(${JSON.stringify(input.realGit)}, mapped, { env: process.env, stdio: "inherit" });
process.exit(result.status ?? 1);
`);
chmodSync(input.path, 0o755);
}