Atomic-replace `oidc_token.json` with the refreshed bundle. Strips `None` values to match the Rust writer's `skip_serializing_if = "Option::is_none"` behavior so a Python- written file is byte-identical in shape to what the CLI writes. Uses `tempfile.mkstemp` (PID +
(self, bundle: dict)
| 1271 | } |
| 1272 | |
| 1273 | def _write_to_disk(self, bundle: dict) -> None: |
| 1274 | """Atomic-replace `oidc_token.json` with the refreshed bundle. |
| 1275 | |
| 1276 | Strips `None` values to match the Rust writer's |
| 1277 | `skip_serializing_if = "Option::is_none"` behavior so a Python- |
| 1278 | written file is byte-identical in shape to what the CLI writes. |
| 1279 | |
| 1280 | Uses `tempfile.mkstemp` (PID + random suffix) so two writers |
| 1281 | racing on the same gateway directory don't share a tmp file |
| 1282 | and trample each other's content. Each writer gets a unique |
| 1283 | path; `.replace()` is atomic per-writer, and POSIX rename |
| 1284 | semantics ensure the final `oidc_token.json` is always |
| 1285 | complete-and-readable to anyone observing. |
| 1286 | """ |
| 1287 | path = self._gateway_dir / "oidc_token.json" |
| 1288 | serializable = {k: v for k, v in bundle.items() if v is not None} |
| 1289 | payload = json.dumps(serializable, indent=2) |
| 1290 | |
| 1291 | # mkstemp creates the file with mode 0600 already on POSIX |
| 1292 | # (it uses O_CREAT | O_EXCL with restrictive umask), so chmod |
| 1293 | # is a belt-and-braces step for filesystems that don't honor |
| 1294 | # the initial mode. |
| 1295 | fd, tmp_name = tempfile.mkstemp( |
| 1296 | prefix=".oidc_token.", |
| 1297 | suffix=".tmp", |
| 1298 | dir=str(self._gateway_dir), |
| 1299 | ) |
| 1300 | tmp_path = pathlib.Path(tmp_name) |
| 1301 | try: |
| 1302 | with os.fdopen(fd, "w", encoding="utf-8") as f: |
| 1303 | f.write(payload) |
| 1304 | with contextlib.suppress(OSError): |
| 1305 | tmp_path.chmod(0o600) |
| 1306 | tmp_path.replace(path) |
| 1307 | except BaseException: |
| 1308 | # Clean up our tmp on failure so we don't leave orphaned |
| 1309 | # `.oidc_token.<rand>.tmp` files lying around. The replace |
| 1310 | # already moved the file on the success path. |
| 1311 | with contextlib.suppress(OSError): |
| 1312 | tmp_path.unlink() |
| 1313 | raise |
| 1314 | |
| 1315 | |
| 1316 | def _make_cluster_bearer_provider( |