From f86f39ef2b7098fb5251946948cf1637fbae9858 Mon Sep 17 00:00:00 2001 From: Miguel Angel Simon Sierra Date: Sat, 29 Aug 2026 11:50:34 -0400 Subject: [PATCH] fix(cli): keep the exposure disclosure on both consent branches The claim-link fix dropped "public" from the shared bold line and replaced, rather than supplemented, the dim line on the signed-in branch. A signed-in publisher then approved the upload without being told anywhere in the flow that the artifact is reachable by anyone holding the URL: the owned result block prints Project / Files / URL / Status, and "Public" only appears on the anonymous branch. The disclosure is true for an owned project, not defensive boilerplate. The published-project read is the one hyperframes route with no authentication decorator, so any URL holder can open it; --public governs whether the CLAIMED session is public in the web app, not whether the link is readable. Restore "stable public URL" and lead the signed-in line with the same exposure sentence, keeping only the claim half branch-specific. A parameterised test now asserts both branches carry it. --- packages/cli/src/commands/publish.test.ts | 15 ++++++++++++++- packages/cli/src/commands/publish.ts | 12 +++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/packages/cli/src/commands/publish.test.ts b/packages/cli/src/commands/publish.test.ts index b488a7475..8efca5695 100644 --- a/packages/cli/src/commands/publish.test.ts +++ b/packages/cli/src/commands/publish.test.ts @@ -138,7 +138,20 @@ describe("publish consent notice", () => { it("tells a signed-in publisher there is no claim link", async () => { const output = await runConsent({ type: "api_key", key: "k", source: "env" }); - expect(output).toContain("owned by your account"); + expect(output).toContain("you own it on publish and there is no claim link"); expect(output).not.toContain("claim it after authenticating"); }); + + it.each([ + ["anonymous", null], + ["signed in", { type: "api_key", key: "k", source: "env" }], + ])("discloses the exposure before uploading (%s)", async (_label, credential) => { + // The consent prompt is the only place the user is told the artifact is world-readable: + // the result block prints no exposure line on the owned branch. Dropping it from either + // branch means someone approves an upload without being told who can reach it. + const output = await runConsent(credential); + + expect(output).toContain("creates a stable public URL"); + expect(output).toContain("Anyone with the URL can open the published project"); + }); }); diff --git a/packages/cli/src/commands/publish.ts b/packages/cli/src/commands/publish.ts index fbc7fc14c..b3e290adc 100644 --- a/packages/cli/src/commands/publish.ts +++ b/packages/cli/src/commands/publish.ts @@ -126,15 +126,17 @@ export default defineCommand({ if (args.yes !== true) { console.log(); console.log( - ` ${c.bold("hyperframes publish uploads this project and creates a stable URL.")}`, + ` ${c.bold("hyperframes publish uploads this project and creates a stable public URL.")}`, ); - // Only an anonymous publish gets a claim token; an authenticated one is owned on - // creation. Promising a claim step to a signed-in user sends them looking for a - // token the server never issued. + // Both branches must state the exposure — the published project is readable by anyone + // holding the URL whether or not it is owned. Only the claim half differs: an + // anonymous publish gets a claim token, an authenticated one is owned on creation, so + // promising a claim step to a signed-in user sends them looking for a token the server + // never issued. console.log( credential === null ? ` ${c.dim("Anyone with the URL can open the published project and claim it after authenticating.")}` - : ` ${c.dim("You are signed in, so the project is owned by your account on publish. There is no claim link.")}`, + : ` ${c.dim("Anyone with the URL can open the published project. You are signed in, so you own it on publish and there is no claim link.")}`, ); console.log(); const approved = await clack.confirm({ message: "Publish this project?" });