Use explicit Blob credentials for state sync

This commit is contained in:
Theodore Song
2026-08-02 14:41:49 -04:00
parent a4402134ff
commit ecbdbf4cbf
+12 -7
View File
@@ -9,6 +9,11 @@ const LIVE_KEY = "pma_live_readiness_v1";
const AGENT_IDS = ["value", "momentum", "favorite", "longshot", "diversifier", "catalyst", "reversal", "breakout", "tailalpha", "conviction"]; const AGENT_IDS = ["value", "momentum", "favorite", "longshot", "diversifier", "catalyst", "reversal", "breakout", "tailalpha", "conviction"];
const LIMITS = { closed: 80, history: 160, snapshots: 240, suggestions: 900, paperHistory: 120, paperSnapshots: 120, audit: 120 }; const LIMITS = { closed: 80, history: 160, snapshots: 240, suggestions: 900, paperHistory: 120, paperSnapshots: 120, audit: 120 };
function withBlobAuth(options = {}) {
const token = process.env.BLOB_READ_WRITE_TOKEN;
return token ? { ...options, token } : options;
}
async function readJsonBlob() { async function readJsonBlob() {
let primaryError = null; let primaryError = null;
try { try {
@@ -30,10 +35,10 @@ async function readJsonBlob() {
} }
async function readBlobJson(pathname) { async function readBlobJson(pathname) {
const blob = await get(pathname, { const blob = await get(pathname, withBlobAuth({
access: "private", access: "private",
headers: { "cache-control": "no-cache" }, headers: { "cache-control": "no-cache" },
}); }));
if (!blob || blob.statusCode !== 200 || !blob.stream) return null; if (!blob || blob.statusCode !== 200 || !blob.stream) return null;
const text = await new Response(blob.stream).text(); const text = await new Response(blob.stream).text();
return text ? JSON.parse(text) : null; return text ? JSON.parse(text) : null;
@@ -43,7 +48,7 @@ async function latestVersionedStateBlob() {
let cursor; let cursor;
let newest = null; let newest = null;
do { do {
const page = await list({ prefix: STATE_VERSION_PREFIX, limit: 1000, cursor }); const page = await list(withBlobAuth({ prefix: STATE_VERSION_PREFIX, limit: 1000, cursor }));
for (const blob of page.blobs || []) { for (const blob of page.blobs || []) {
if (!newest || new Date(blob.uploadedAt).getTime() > new Date(newest.uploadedAt).getTime()) newest = blob; if (!newest || new Date(blob.uploadedAt).getTime() > new Date(newest.uploadedAt).getTime()) newest = blob;
} }
@@ -218,21 +223,21 @@ export default async function handler(req, res) {
return conflictResponse(res, "Incoming state would replace newer active positions with stale cash-only data", current); return conflictResponse(res, "Incoming state would replace newer active positions with stale cash-only data", current);
} }
const state = { version: 1, updated_at: new Date().toISOString(), items: compactItems(incomingItems) }; const state = { version: 1, updated_at: new Date().toISOString(), items: compactItems(incomingItems) };
await put(STATE_PATH, JSON.stringify(state), { await put(STATE_PATH, JSON.stringify(state), withBlobAuth({
access: "private", access: "private",
allowOverwrite: true, allowOverwrite: true,
contentType: "application/json", contentType: "application/json",
cacheControlMaxAge: 0, cacheControlMaxAge: 0,
}); }));
if (process.env.PMA_ENABLE_STATE_HISTORY === "true") { if (process.env.PMA_ENABLE_STATE_HISTORY === "true") {
const versionedPath = `${STATE_VERSION_PREFIX}${Date.now()}-${Math.random().toString(36).slice(2)}.json`; const versionedPath = `${STATE_VERSION_PREFIX}${Date.now()}-${Math.random().toString(36).slice(2)}.json`;
try { try {
await put(versionedPath, JSON.stringify(state), { await put(versionedPath, JSON.stringify(state), withBlobAuth({
access: "private", access: "private",
allowOverwrite: false, allowOverwrite: false,
contentType: "application/json", contentType: "application/json",
cacheControlMaxAge: 0, cacheControlMaxAge: 0,
}); }));
} catch { } catch {
// The shared state is authoritative; backup retention must not block a cycle. // The shared state is authoritative; backup retention must not block a cycle.
} }