fix(dashboard): authenticate artifact media URLs (#2144)

## Summary
- append the existing same-origin daemon token fallback to artifact
media URLs used by image, video, and link navigation
- preserve project scoping and artifact ID encoding
- add a focused regression test and patch changeset

## Root cause
Artifact metadata loads through authenticated `fetch`, but previews and
links use raw browser navigation (`<img src>`, `<video src>`, and
anchors), which cannot attach the dashboard bearer header. The media
endpoint therefore returned `401 Valid bearer token required` even
though the dashboard itself was authenticated.

## Verification
- `pnpm --filter @fusion/dashboard exec vitest run --project
dashboard-app-quality-foundation-api app/__tests__/api-artifacts.test.ts
--reporter=dot`
- `pnpm lint`
- `pnpm --filter @fusion/dashboard typecheck`
- `pnpm check:changesets --strict`
- `pnpm build`
- `FUSION_PG_TEST_URL_BASE=postgresql://plarson@127.0.0.1:55432
VITEST_MAX_WORKERS=1 nix shell nixpkgs#postgresql --command pnpm
test:gate`

The broader dashboard foundation API shard was also attempted but
aborted in Node after repeated unmanaged-file-descriptor warnings; the
focused regression and canonical merge gate both pass.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed protected artifact images and links so they load correctly in
authenticated dashboards.
* Added authentication tokens to generated artifact media URLs for
reliable previews and navigation.

* **Tests**
* Added coverage verifying authenticated artifact media URLs include the
expected token and parameters.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Phil Larson
2026-07-15 14:40:38 -07:00
committed by GitHub
parent 564187332d
commit 329fc1f664
3 changed files with 33 additions and 1 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: Fix protected image artifacts so previews and links load in authenticated dashboards.
category: fix
dev: Artifact media URLs now use the existing same-origin query-token fallback required by browser image and link navigation.

View File

@@ -0,0 +1,21 @@
import { afterEach, describe, expect, it } from "vitest";
import { artifactMediaUrl } from "../api";
import { clearAuthToken, setAuthToken } from "../auth";
afterEach(() => {
clearAuthToken();
});
describe("artifactMediaUrl", () => {
/*
* FNXC:ArtifactMediaAuth 2026-07-15-14:24:
* Browser-native image, video, and link requests cannot attach the dashboard's Authorization header. Keep this regression focused on the generated URL contract: encoded artifact id and project scope survive while the existing same-origin fn_token fallback is appended.
*/
it("appends the daemon token for image and link navigation", () => {
setAuthToken("daemon-token");
expect(artifactMediaUrl("artifact/with spaces", "project-1")).toBe(
"/api/artifacts/artifact%2Fwith%20spaces/media?projectId=project-1&fn_token=daemon-token",
);
});
});

View File

@@ -1738,7 +1738,11 @@ export async function fetchArtifacts(
}
export function artifactMediaUrl(id: string, projectId?: string): string {
return buildApiUrl(withProjectId(`/artifacts/${encodeURIComponent(id)}/media`, projectId));
/*
* FNXC:ArtifactMediaAuth 2026-07-15-14:24:
* Artifact previews and links use browser-native navigation, which cannot send the bearer header used by fetch. Reuse appendTokenQuery so authenticated media loads while its dashboard-owned URL guard prevents leaking the daemon token cross-origin.
*/
return appendTokenQuery(buildApiUrl(withProjectId(`/artifacts/${encodeURIComponent(id)}/media`, projectId)));
}
/*