fix: classify transient GitHub connectivity
Merge PR #102 after rebasing onto current master and validating focused GitHub transient/Code Queue preflight behavior. GitHub DNS/API failures now classify as retryable github-transient with retry/backoff or keep-fresh-heartbeat-task guidance.
This commit is contained in:
@@ -202,6 +202,21 @@ async function startMockGitHub(): Promise<{ baseUrl: string; requests: MockReque
|
||||
};
|
||||
}
|
||||
|
||||
async function startResetGitHub(): Promise<{ baseUrl: string; close: () => Promise<void> }> {
|
||||
const server = createServer((req) => {
|
||||
req.socket.destroy();
|
||||
});
|
||||
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
||||
const address = server.address();
|
||||
assertCondition(typeof address === "object" && address !== null, "reset mock server should expose address");
|
||||
const port = (address as AddressInfo).port;
|
||||
assertCondition(typeof port === "number", "reset mock server should expose port");
|
||||
return {
|
||||
baseUrl: `http://127.0.0.1:${port}`,
|
||||
close: () => new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())),
|
||||
};
|
||||
}
|
||||
|
||||
function dataOf(response: JsonRecord): JsonRecord {
|
||||
assertCondition(response.ok === true, "CLI command should succeed", response);
|
||||
assertCondition(typeof response.data === "object" && response.data !== null && !Array.isArray(response.data), "response data should be object", response);
|
||||
@@ -383,6 +398,24 @@ export async function runGhCliPrContract(): Promise<JsonRecord> {
|
||||
await mock.close();
|
||||
}
|
||||
|
||||
const resetMock = await startResetGitHub();
|
||||
try {
|
||||
const transient = await runCli(["gh", "auth", "status", "--repo", "pikasTech/unidesk"], {
|
||||
GH_TOKEN: "contract-token",
|
||||
UNIDESK_GITHUB_API_URL: resetMock.baseUrl,
|
||||
});
|
||||
assertCondition(transient.status !== 0, "GitHub DNS/API transient should fail structurally", transient.json ?? { stdout: transient.stdout });
|
||||
const transientData = failedDataOf(transient.json ?? {});
|
||||
assertCondition(transientData.degradedReason === "github-transient", "GitHub DNS/API transient should not be auth-missing or semantic failure", transientData);
|
||||
assertCondition(transientData.runnerDisposition === "infra-blocked", "GitHub transient should remain infra-blocked", transientData);
|
||||
const transientDetails = transientData.details as JsonRecord;
|
||||
assertCondition(transientDetails.retryable === true, "GitHub transient should be retryable", transientDetails);
|
||||
assertCondition(transientDetails.commanderAction === "retry-backoff-or-keep-running-if-heartbeat-fresh", "GitHub transient should expose bounded commander action", transientDetails);
|
||||
assertCondition(!transient.stdout.includes("contract-token"), "GitHub transient output must not print token values", { stdout: transient.stdout });
|
||||
} finally {
|
||||
await resetMock.close();
|
||||
}
|
||||
|
||||
const title = "contract pr create";
|
||||
const bodyFile = join(tmpdir(), `unidesk-gh-pr-contract-${process.pid}.md`);
|
||||
writeFileSync(bodyFile, "Line 1\n`code`\n| a | b |\n", "utf8");
|
||||
@@ -519,6 +552,7 @@ export async function runGhCliPrContract(): Promise<JsonRecord> {
|
||||
"pr read/view accept owner/repo#number shorthand and reject conflicting --repo",
|
||||
"pr read/view --raw is explicit full disclosure",
|
||||
"pr read normalizes open and merged lifecycle fields from REST",
|
||||
"GitHub DNS/API transients are retryable and distinct from auth or PR semantic failures",
|
||||
"pr view closeout metadata fields are accepted and hydrated through GraphQL",
|
||||
"pr read unsupported fields fail structurally with supported closeout fields listed",
|
||||
"pr create dry-run exposes planned operation",
|
||||
|
||||
Reference in New Issue
Block a user