Skip to content

SoF export: re-sign S3 pre-signed download URLs on each manifest poll #145

Description

@smunini

Context

For S3-backed SoF exports ($viewdefinition-export / $sqlquery-export), pre-signed GET URLs are generated once at shard-write time and baked into the job's CompletedFile.url (crates/rest/src/export/sink.rs, S3Sink::write_shard). Every subsequent status poll returns those same URLs in the manifest.

The spec (operations-common / #365) requires output.location download URLs to remain valid for at least 24 hours after export completion, and the completion poll advertises Expires: completed_at + 24h. The default presign TTL is now 24h (HFS_EXPORT_PRESIGN_TTL_SECS=86400), but the TTL clock starts at write time, not completion time — and a client that re-polls the manifest 23 hours in still receives URLs that are about to expire (or already have, if the operator configured a shorter TTL).

Proposed change

Store the S3 object key (not the pre-signed URL) in CompletedFile, and generate fresh pre-signed URLs at manifest-render time (build_completion_manifest in crates/rest/src/handlers/sof/export.rs). Each poll then hands out URLs with a full TTL window, and the Expires header can reflect the actual presign expiry.

Notes:

  • FilesystemSink URLs are server-routed and unaffected; the change can be scoped to how the manifest resolves a CompletedFile into a URL (e.g. an ExportSink::download_url(job_id, filename) method, with the FS/in-memory sinks returning their stable URLs).
  • Presigning requires an async call into the AWS SDK from the status handler; the existing block_in_place pattern in S3Sink can be reused or the handler made to await it directly.
  • Related: pre-signed URLs are also capped by the signing credentials' lifetime (e.g. STS session duration), which can silently undercut the requested TTL — worth a docs note for operators using temporary credentials.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions