From 9fdf3d2f0dd7807e952f3ba56861f51e95f5ceaf Mon Sep 17 00:00:00 2001 From: DevITWay | Pavel Volkov Date: Tue, 27 Oct 2026 11:11:49 -0400 Subject: [PATCH] docs(storage): a GCS emulator needs a disable_oauth key file; fake-gcs-server is not one The GCS doc comments named fake-gcs-server as a supported emulator. It is not: it has no XML API object PUT and does not handle x-goog-copy-source, so NORA cannot write to it on any version. They also implied an http:// base_url is enough. It skips request signing, but object_store's GCS client still asks the credential provider for a token on writes, so without key material every PUT fails with "Error getting token response body". A service-account file with "disable_oauth": true (private_key, private_key_id and client_email present but unused) makes writes work against an XML API emulator. --- nora-registry/src/config/storage.rs | 9 +++++++-- nora-registry/src/storage/object.rs | 6 ++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/nora-registry/src/config/storage.rs b/nora-registry/src/config/storage.rs index f070d01a..15b9b189 100644 --- a/nora-registry/src/config/storage.rs +++ b/nora-registry/src/config/storage.rs @@ -47,10 +47,15 @@ pub struct StorageConfig { /// Workload Identity / GCE service accounts need no key material). #[serde(default)] pub gcs_service_account_path: Option, - /// GCS: endpoint override for emulators (fake-gcs-server) or Private - /// Google Access endpoints. Unset = https://storage.googleapis.com. + /// GCS: endpoint override for emulators or Private Google Access + /// endpoints. Unset = https://storage.googleapis.com. /// Emulator-only caveat: an `http://` override also disables request /// signing — do not point this at a plaintext non-emulator endpoint. + /// Writes still ask for a token, so against an emulator also set + /// `gcs_service_account_path` to a key file with `"disable_oauth": true` + /// (`private_key`, `private_key_id` and `client_email` must be present but + /// are not used). The emulator must serve the GCS XML API, including + /// object PUT and `x-goog-copy-source` copies: fake-gcs-server does not. #[serde(default)] pub gcs_base_url: Option, } diff --git a/nora-registry/src/storage/object.rs b/nora-registry/src/storage/object.rs index e4cf39ae..5b4f6f00 100644 --- a/nora-registry/src/storage/object.rs +++ b/nora-registry/src/storage/object.rs @@ -118,8 +118,10 @@ impl ObjectStorage { /// `GOOGLE_APPLICATION_CREDENTIALS`, ...), then the instance metadata /// server — so GKE Workload Identity and GCE service accounts work with no /// key material at all. `base_url` overrides the endpoint for emulators - /// (fake-gcs-server) or private access endpoints; an `http://` base_url - /// also skips request signing (emulators don't verify signatures). + /// or private access endpoints; an `http://` base_url also skips request + /// signing (emulators don't verify signatures). object_store still asks the + /// credential provider for a token on writes, so an emulator needs a key + /// file with `"disable_oauth": true` (see `StorageConfig::gcs_base_url`). pub fn new_gcs( bucket: &str, service_account_path: Option<&str>,