Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions packages/deploy-cloudflare/src/existing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { isRecord } from '@void/deploy-core';
import { parseRootWranglerConfig } from './config.ts';
import { isCleanCommandExit, isWorkerNotFound, type CloudflareCommandRunner } from './execute.ts';
import type { CloudflareOperation } from './operations.ts';
import { isVoidSecretOnlyDraft, isWranglerSecretOnlyDraft } from './secret-draft.ts';
import {
isVoidSecretDraftHeader,
isVoidSecretOnlyDraft,
isWranglerSecretOnlyDraft,
} from './secret-draft.ts';

export type ExistingCloudflareWorker = {
versionId: string;
Expand Down Expand Up @@ -115,9 +119,10 @@ async function readCloudflareWorker(
if (
proveSecretDraft &&
!isSecretOnlyDraft &&
isRecord(version.annotations) &&
Object.keys(version.annotations).length === 1 &&
version.annotations['workers/triggered_by'] === 'secret'
((isRecord(version.annotations) &&
Object.keys(version.annotations).length === 1 &&
version.annotations['workers/triggered_by'] === 'secret') ||
isVoidSecretDraftHeader(version))
) {
const source = await read({ type: 'versions.view', versionId, includeSource: true, ...target });
if (source?.id === versionId) {
Expand Down
2 changes: 1 addition & 1 deletion packages/deploy-cloudflare/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export {
} from './version.ts';
export { createCloudflareMetadataRunner } from './metadata.ts';
export { cloudflareCommandDiagnostic } from './diagnostics.ts';
export { VOID_SECRET_DRAFT_SOURCE } from './secret-draft.ts';
export { VOID_SECRET_DRAFT_MESSAGE, VOID_SECRET_DRAFT_SOURCE } from './secret-draft.ts';

export type {
CloudflareOperation,
Expand Down
33 changes: 28 additions & 5 deletions packages/deploy-cloudflare/src/secret-draft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,33 @@ export function isWranglerSecretOnlyDraft(entry: Record<string, unknown>): boole
export const VOID_SECRET_DRAFT_SOURCE =
'export default { fetch() { return new Response(""); } };\n';

/** Prove a cf-created placeholder from the exact immutable version's source. */
/** Message on the placeholder that Void's secret transport deploys to a Worker without code. */
export const VOID_SECRET_DRAFT_MESSAGE = 'void:secret-draft';

/**
* Annotations of a Void secret placeholder, checked before its source is inspected:
* - `api`: the secret transport uploaded and deployed the placeholder and its first secrets in
* one Workers API request.
* - `cf_cli`: `cf workers secrets` added secrets to a deployed placeholder.
*/
export function isVoidSecretDraftHeader(entry: Record<string, unknown>): boolean {
if (!isRecord(entry.annotations)) {
return false;
}
const annotations = entry.annotations;
const keys = Object.keys(annotations);
if (entry.source === 'cf_cli') {
return keys.length === 1 && annotations['workers/triggered_by'] === 'secret';
}
return (
entry.source === 'api' &&
keys.length === 2 &&
annotations['workers/message'] === VOID_SECRET_DRAFT_MESSAGE &&
annotations['workers/triggered_by'] === 'create_version_api'
);
}

/** Prove a Void secret placeholder from the exact immutable version's source. */
export function isVoidSecretOnlyDraft(entry: Record<string, unknown>): boolean {
const metadataFields = new Set([
'id',
Expand All @@ -90,10 +116,7 @@ export function isVoidSecretOnlyDraft(entry: Record<string, unknown>): boolean {
]);
if (
Object.keys(entry).some((key) => !metadataFields.has(key)) ||
entry.source !== 'cf_cli' ||
!isRecord(entry.annotations) ||
Object.keys(entry.annotations).length !== 1 ||
entry.annotations['workers/triggered_by'] !== 'secret' ||
!isVoidSecretDraftHeader(entry) ||
entry.main_module !== 'index.js' ||
!Array.isArray(entry.urls) ||
entry.urls.length !== 0 ||
Expand Down
11 changes: 5 additions & 6 deletions packages/deploy-cloudflare/src/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import {
} from './execute.ts';
import type { CloudflareUploadResult } from './operations.ts';
import {
isVoidSecretDraftHeader,
isVoidSecretOnlyDraft,
isWranglerSecretOnlyDraft,
VOID_SECRET_DRAFT_MESSAGE,
VOID_SECRET_DRAFT_SOURCE,
} from './secret-draft.ts';

Expand Down Expand Up @@ -1894,8 +1896,9 @@ async function readCloudflareVersionInspection(
let draft = entry;
let draftUnknown = false;
if (
annotations?.['workers/triggered_by'] === 'secret' &&
Object.keys(annotations).length === 1 &&
((annotations?.['workers/triggered_by'] === 'secret' &&
Object.keys(annotations).length === 1) ||
isVoidSecretDraftHeader(entry)) &&
!isWranglerSecretOnlyDraft(entry)
) {
draftUnknown = true;
Expand Down Expand Up @@ -1935,10 +1938,6 @@ async function readCloudflareVersionInspection(
return null;
}

// Message Void's secret transport gives the zero-binding placeholder it deploys when a Worker
// does not exist yet (packages/void cloudflare-operation-process.ts).
const VOID_SECRET_DRAFT_MESSAGE = 'void:secret-draft';

/**
* Recovery-only proof that a version is Void's secret placeholder: its marker plus the exact
* placeholder source, with no binding other than secrets. It may have zero bindings, so it is
Expand Down
14 changes: 14 additions & 0 deletions packages/deploy-cloudflare/test/secret-draft-fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,17 @@ export function voidSecretDraftVersion(): Record<string, unknown> & {
author_id: 'synthetic-author',
};
}

/** Sanitized shape of the placeholder that Void's transport uploads and deploys in one request. */
export function apiSecretDraftVersion(): ReturnType<typeof voidSecretDraftVersion> {
return {
...voidSecretDraftVersion(),
number: 1,
startup_time_ms: 0,
annotations: {
'workers/message': 'void:secret-draft',
'workers/triggered_by': 'create_version_api',
},
source: 'api',
};
}
10 changes: 6 additions & 4 deletions packages/deploy-cloudflare/test/unit/existing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from '../../src/existing.ts';
import type { CloudflareOperation } from '../../src/operations.ts';
import { operationFixture } from '../operation-fixture.ts';
import { voidSecretDraftVersion } from '../secret-draft-fixture.ts';
import { apiSecretDraftVersion, voidSecretDraftVersion } from '../secret-draft-fixture.ts';

const worker: ExistingCloudflareWorker = {
versionId: 'original',
Expand Down Expand Up @@ -498,10 +498,11 @@ describe('existing Worker preservation', () => {
);
});

it.each(['placeholder', 'real-code', 'owner-drift'] as const)(
it.each(['placeholder', 'api-placeholder', 'real-code', 'owner-drift'] as const)(
'verifies immutable SDK secret-draft proof before its first DO migration: %s',
async (scenario) => {
const source = voidSecretDraftVersion();
const source =
scenario === 'api-placeholder' ? apiSecretDraftVersion() : voidSecretDraftVersion();
if (scenario === 'real-code') {
source.modules[0]!.content_base64 = Buffer.from(
'export default { fetch() { return new Response("app"); } };',
Expand Down Expand Up @@ -531,6 +532,7 @@ describe('existing Worker preservation', () => {
stderr: '',
data: {
id: operation.versionId,
source: source.source,
annotations: source.annotations,
resources: {
bindings: source.bindings,
Expand All @@ -557,7 +559,7 @@ describe('existing Worker preservation', () => {
apiBaseUrl: 'https://api.cloudflare.test/client/v4',
readMigrationTag: async () => null,
});
if (scenario === 'placeholder') {
if (scenario === 'placeholder' || scenario === 'api-placeholder') {
await expect(inspection).resolves.toBeUndefined();
} else {
await expect(inspection).rejects.toThrow(
Expand Down
22 changes: 21 additions & 1 deletion packages/deploy-cloudflare/test/unit/secret-draft.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
import { describe, expect, it } from 'vite-plus/test';
import { isVoidSecretOnlyDraft, isWranglerSecretOnlyDraft } from '../../src/secret-draft.ts';
import { voidSecretDraftVersion } from '../secret-draft-fixture.ts';
import { apiSecretDraftVersion, voidSecretDraftVersion } from '../secret-draft-fixture.ts';

describe('immutable SDK secret draft proof', () => {
it('recognizes the placeholder that the secret transport deploys in one request', () => {
const draft = apiSecretDraftVersion();
expect(isVoidSecretOnlyDraft(draft)).toBe(true);
expect(isVoidSecretOnlyDraft({ ...draft, source: 'cf_cli' })).toBe(false);
expect(isVoidSecretOnlyDraft({ ...draft, source: 'dash' })).toBe(false);
expect(
isVoidSecretOnlyDraft({
...draft,
annotations: { ...draft.annotations, 'workers/tag': 'release' },
}),
).toBe(false);
expect(
isVoidSecretOnlyDraft({
...draft,
annotations: { 'workers/triggered_by': 'create_version_api' },
}),
).toBe(false);
expect(isVoidSecretOnlyDraft({ ...draft, bindings: [], env: {} })).toBe(false);
});

it('recognizes the actual cf placeholder without treating its compatibility date as proof', () => {
const draft = voidSecretDraftVersion();
expect(isWranglerSecretOnlyDraft(draft)).toBe(false);
Expand Down
52 changes: 47 additions & 5 deletions packages/deploy-cloudflare/test/unit/version.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
type CloudflareTriggerConfig,
} from '../../src/index.ts';
import { operationFixture } from '../operation-fixture.ts';
import { voidSecretDraftVersion } from '../secret-draft-fixture.ts';
import { apiSecretDraftVersion, voidSecretDraftVersion } from '../secret-draft-fixture.ts';

const CURRENT = '11111111-1111-4111-8111-111111111111';
const NEXT = '22222222-2222-4222-8222-222222222222';
Expand Down Expand Up @@ -58,7 +58,10 @@ function readConfigArg(args: Array<string>): Record<string, unknown> {
return JSON.parse(readFileSync(args[args.indexOf('-c') + 1]!, 'utf8')) as Record<string, unknown>;
}

function sdkDraftActivation(source: Record<string, unknown> = voidSecretDraftVersion()) {
function sdkDraftActivation(
source: Record<string, unknown> = voidSecretDraftVersion(),
listed: Record<string, unknown> = { annotations: { 'workers/triggered_by': 'secret' } },
) {
const events: Array<string> = [];
const operations: Array<CloudflareOperation> = [];
const message = encodeCloudflareVersionMessage([], triggersWith());
Expand All @@ -81,9 +84,7 @@ function sdkDraftActivation(source: Record<string, unknown> = voidSecretDraftVer
{
id: CURRENT,
number: 2,
annotations: ordinary
? { 'workers/message': message }
: { 'workers/triggered_by': 'secret' },
...(ordinary ? { annotations: { 'workers/message': message } } : listed),
},
...(uploaded
? [{ id: NEXT, number: 3, annotations: { 'workers/message': message } }]
Expand Down Expand Up @@ -625,6 +626,47 @@ describe('Cloudflare version activation', () => {
).toBe(false);
});

it('publishes over the placeholder that the secret transport deployed in one request', async () => {
const draft = apiSecretDraftVersion();
const fixture = sdkDraftActivation(draft, {
source: draft.source,
annotations: draft.annotations,
});
const result = await activateCloudflareVersion(fixture.options);
expect(result).toMatchObject({ ok: true, versionId: NEXT, previousVersionId: CURRENT });
expect(fixture.events.slice(0, 3)).toEqual(['source', 'pin', 'publish']);
expect(fixture.pinActiveSecrets).toHaveBeenCalledExactlyOnceWith(CURRENT, [
{ name: 'TOKEN', type: 'secret_text' },
]);
expect(fixture.operations.filter((op) => op.type === 'worker.deploy')).toHaveLength(1);
});

it.each([
[
'application code',
{ modules: [{ ...apiSecretDraftVersion().modules[0], content_base64: 'YXBw' }] },
],
['another source', { source: 'dash' }],
[
'another message',
{
annotations: { 'workers/message': 'release', 'workers/triggered_by': 'create_version_api' },
},
],
])(
'does not treat an API-deployed version with %s as the placeholder',
async (_label, change) => {
const draft: Record<string, unknown> = { ...apiSecretDraftVersion(), ...change };
const fixture = sdkDraftActivation(draft, {
source: draft.source,
annotations: draft.annotations,
});
await activateCloudflareVersion(fixture.options);
expect(fixture.operations.some((op) => op.type === 'worker.deploy')).toBe(false);
expect(fixture.events).not.toContain('publish');
},
);

it('publishes an exact private SDK draft once, proving secrets and callbacks before readiness', async () => {
const fixture = sdkDraftActivation({
...voidSecretDraftVersion(),
Expand Down
Loading
Loading