Cache issued tgz in memory for one-time download

Instead of streaming the tgz directly to the response (which was
fragile under server write timeouts), handleIssueCert now:
- Builds the tgz into a bytes.Buffer
- Stores it in a sync.Map (tgzCache) under a random 16-byte hex token
- Redirects the browser to /pki/download/{token}

handleTGZDownload serves the cached bytes via LoadAndDelete, so the
archive is removed from memory after the first (and only) download.
An unknown or already-used token returns 404.

Also adds TestHandleTGZDownload covering the one-time-use and
not-found cases, and wires issueCertFn into mockVault.

Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
2026-03-15 13:44:32 -07:00
parent 4deb469a9d
commit 4469c650cc
3 changed files with 112 additions and 19 deletions

View File

@@ -10,6 +10,7 @@ import (
"io/fs"
"log/slog"
"net/http"
"sync"
"time"
"github.com/go-chi/chi/v5"
@@ -42,6 +43,12 @@ type vaultBackend interface {
Close() error
}
// tgzEntry holds a cached tgz archive pending download.
type tgzEntry struct {
filename string
data []byte
}
// WebServer is the standalone web UI server.
type WebServer struct {
cfg *config.Config
@@ -49,6 +56,7 @@ type WebServer struct {
logger *slog.Logger
httpSrv *http.Server
staticFS fs.FS
tgzCache sync.Map // key: UUID string → *tgzEntry
}
// New creates a new WebServer. It dials the vault gRPC endpoint.