Serve call audio through c2-core instead of GCS signed URLs
Build & Deploy / Build & push images (push) Successful in 4m0s
Build & Deploy / Deploy to VM (push) Failing after 2m34s

upload_audio() could only sign a URL when GCP_CREDENTIALS_PATH pointed at a
service-account key file. The deployed VM runs on Application Default
Credentials with no key file, so every upload silently took the fallback
branch and returned a bare gs:// URI. That broke two things at once:

  * Browsers cannot fetch a gs:// URI, so no recording was ever playable.
  * _public_url_to_gcs_uri() only matched https://storage.googleapis.com/ and
    returned None for it, so `if gcs_uri:` in the upload path was always false
    and transcription never ran. Nothing was logged, which is why this looked
    like an OpenAI credits problem rather than a storage one.

The fallback also interpolated the client-supplied filename instead of the
call_id-derived safe name, so the URI did not even name the object written.

Calls now store only the canonical gs:// location. A short-lived playback link
is minted per read as an HMAC over (call_id, expiry) keyed by SERVICE_KEY, and
audio is served from the private bucket by the new /media route. An <audio src>
cannot carry an Authorization header, so the link has to be the credential;
that router is therefore public with the check done inline, as enrollment.py
already does. Signing GCS URLs from the VM would have needed a
serviceAccountTokenCreator grant on its own service account — this avoids the
IAM change entirely and keeps the bucket private.

gcs_uri_for_call() reconstructs the object name from call_id, so recordings
made before this fix are reachable again without a data migration.

Frontend rows come straight from Firestore via onSnapshot and never see a
server-minted field, so CallRow fetches the link lazily on expand.

Also removes the last long-lived (1 year) signed URL and the log line that
printed it.
This commit is contained in:
Logan Cusano
2026-08-16 16:26:41 -04:00
parent a195563da6
commit a2cd2c57ca
10 changed files with 291 additions and 62 deletions
+7
View File
@@ -93,6 +93,13 @@ export interface CallRecord {
freq: number | null;
started_at: string;
ended_at: string | null;
/** Private gs:// object location. Present on the Firestore doc; not playable. */
audio_gcs_uri?: string | null;
/**
* Short-lived playback link. Minted per read by the API — only populated on
* calls fetched via c2api, never on docs read straight from Firestore.
* On pre-fix docs this holds a legacy (unplayable) gs:// URI instead.
*/
audio_url: string | null;
transcript: string | null;
transcript_corrected: string | null;