Skip to content

Commit 6007aec

Browse files
test(operator): cover automation connector rehydration
1 parent fd1f212 commit 6007aec

1 file changed

Lines changed: 103 additions & 0 deletions

File tree

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import fs from "node:fs"
2+
import os from "node:os"
3+
import path from "node:path"
4+
import { spawnSync } from "node:child_process"
5+
6+
const guard = new URL("./codex-automation-connector-rehydration-guard.mjs", import.meta.url).pathname
7+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "codex-automation-connectors-"))
8+
9+
const base = {
10+
operation_id: "op-auto-connectors-1",
11+
turn: {
12+
thread_source: "automation",
13+
is_followup: true,
14+
apps_instructions_before: true,
15+
apps_instructions_after: true,
16+
explicit_apps_disable: false,
17+
canonical_thread_preserved: true,
18+
},
19+
connectors: {
20+
auth_still_valid: true,
21+
required_families: ["gmail", "calendar"],
22+
registered_families: ["gmail", "calendar", "drive"],
23+
read_only_canary_passed: true,
24+
catalog_revision_readback: true,
25+
oauth_reconnect_requested: false,
26+
permission_broadening_requested: false,
27+
},
28+
state: {
29+
task_state_preserved: true,
30+
prior_turn_preserved: true,
31+
external_writes_reconciled: true,
32+
stale_answer_accepted: false,
33+
automatic_replay_requested: false,
34+
unrelated_work_continues: true,
35+
},
36+
continuity_route: {
37+
type: "approved_openai_connector_runtime",
38+
verified: true,
39+
canary_passed: true,
40+
operation_binding_matches: true,
41+
},
42+
}
43+
44+
function run(name, evidence, expectedCode, expectedReason) {
45+
const file = path.join(root, `${name}.json`)
46+
fs.writeFileSync(file, JSON.stringify(evidence))
47+
const result = spawnSync(process.execPath, [guard, "--input", file], { encoding: "utf8" })
48+
const stream = result.status === 0 ? result.stdout : result.stderr || result.stdout
49+
const parsed = JSON.parse(stream)
50+
if (result.status !== expectedCode) throw new Error(`${name}: expected exit ${expectedCode}, got ${result.status}\n${stream}`)
51+
if (parsed.reason !== expectedReason) throw new Error(`${name}: expected ${expectedReason}, got ${parsed.reason}`)
52+
}
53+
54+
run("healthy-followup", structuredClone(base), 0, "automation_connector_catalog_verified")
55+
56+
const disabled = structuredClone(base)
57+
disabled.turn.apps_instructions_after = false
58+
disabled.connectors.registered_families = []
59+
disabled.connectors.read_only_canary_passed = false
60+
disabled.connectors.catalog_revision_readback = false
61+
run("silent-disable", disabled, 75, "automation_followup_silently_disabled_apps")
62+
63+
const missingFamily = structuredClone(base)
64+
missingFamily.connectors.registered_families = ["calendar"]
65+
run("missing-family", missingFamily, 75, "required_connector_families_missing_after_followup")
66+
67+
const noCanary = structuredClone(base)
68+
noCanary.connectors.read_only_canary_passed = false
69+
run("read-canary", noCanary, 75, "connector_read_only_canary_required_after_followup")
70+
71+
const noRevision = structuredClone(base)
72+
noRevision.connectors.catalog_revision_readback = false
73+
run("catalog-revision", noRevision, 75, "connector_catalog_revision_not_verified")
74+
75+
const stale = structuredClone(disabled)
76+
stale.state.stale_answer_accepted = true
77+
stale.turn.explicit_apps_disable = true
78+
run("reject-stale-answer", stale, 75, "required_connector_families_missing_after_followup")
79+
80+
const authMutation = structuredClone(disabled)
81+
authMutation.turn.explicit_apps_disable = true
82+
authMutation.connectors.required_families = []
83+
authMutation.connectors.oauth_reconnect_requested = true
84+
run("preserve-auth", authMutation, 75, "connector_read_only_canary_required_after_followup")
85+
86+
const replay = structuredClone(base)
87+
replay.state.automatic_replay_requested = true
88+
replay.state.external_writes_reconciled = false
89+
run("reject-replay", replay, 64, "automation_replay_rejected_before_state_and_write_reconciliation")
90+
91+
const globalPause = structuredClone(disabled)
92+
globalPause.turn.explicit_apps_disable = true
93+
globalPause.connectors.required_families = []
94+
globalPause.connectors.read_only_canary_passed = true
95+
globalPause.connectors.catalog_revision_readback = true
96+
globalPause.state.unrelated_work_continues = false
97+
run("avoid-global-pause", globalPause, 75, "unrelated_automation_work_should_not_be_globally_paused")
98+
99+
const prohibited = structuredClone(base)
100+
prohibited.continuity_route.type = "model-gateway-auto-select"
101+
run("prohibited-route", prohibited, 64, "prohibited_route_metadata")
102+
103+
console.log(JSON.stringify({ passed: 10 }, null, 2))

0 commit comments

Comments
 (0)