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: 13 additions & 0 deletions docs/guide/platform/installation/maintenance.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,19 @@ Let running rotations finish before you roll back. If an older proxy runs next t

:::

### Change runtime logs {#runtime-logs}

Switch an installed platform between [full and minimal runtime logs](/guide/platform/installation/setup#runtime-logs) with an upgrade:

```sh
void platform upgrade [id] --runtime-logs minimal
void platform upgrade [id] --runtime-logs full
```

Later upgrades keep the setting. The upgrade also changes Workers Logs on the projects' existing deployments. If that step fails, the upgrade still finishes and prints what to run next: `void platform repair [id]` after switching to minimal, or the same upgrade again after switching to full. Records stored before the change are not removed; they expire with Cloudflare's retention.

While runtime logs are minimal, `void platform rollback` refuses a runtime that does not support the setting. Run `void platform upgrade [id] --runtime-logs full` first.

### Platform Workers changed outside Void {#workers-changed-outside-void}

Use Void commands to manage the platform's Workers. If their configuration was changed in Cloudflare, or Void cannot identify the active version, maintenance asks you to approve replacing it. Preview the affected Workers with `--plan`.
Expand Down
19 changes: 19 additions & 0 deletions docs/guide/platform/installation/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,25 @@ Keep the file’s existing `connections` configuration. For `mode: "platform"`,
same-account identity and policy selections are reused. Headless setup requires an
explicit app-management token; it never silently retains an installer-only token.

## Choose what runtime logs record {#runtime-logs}

By default, the platform records each request's URL, console output, and exception messages. Project owners see them with `void project logs`, and administrators with `void platform deployment logs`. They are kept in your Cloudflare account, in Workers Logs and in the platform's log history.

If your apps can put personal data in URLs, logs, or error messages, install with minimal runtime logs:

```sh
void platform install --runtime-logs minimal
```

With minimal runtime logs:

- Platform and project Workers do not send anything to Workers Logs.
- Log history keeps each request's time, method, status, outcome, deployment, log levels, and exception names, but not its URL, log messages, or exception messages.
- `--level` filters still work. `--filter` can match exception names, but not the messages that are no longer recorded.
- Log views say that messages and URLs are not recorded on this platform.

The setting covers the whole platform. To change it later, see [Change runtime logs](/guide/platform/installation/maintenance#runtime-logs).

## Finish login configuration

For Google, create an OAuth client and register the printed callback URL. You
Expand Down
5 changes: 4 additions & 1 deletion docs/reference/cli/platform-installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ void platform install [options] [--yes]
| `--dedicated-zone` | Add zone-wide catch-all routes; valid only when the app domain is the whole zone |
| `--no-dedicated-zone` | Skip zone-wide application catch-all routes |
| `--custom-domains` | Let projects add their own domains; needs a dedicated zone |
| `--runtime-logs <full\|minimal>` | `minimal` keeps request URLs and log and exception messages out of runtime logs |
| `--control-plane-domain <domain>` | Optional API custom hostname; defaults to `workers.dev` |
| `--no-control-plane-domain` | Use the default `workers.dev` API hostname |
| `--dashboard-url <origin>` | HTTPS origin of an optional dashboard deployed separately |
Expand Down Expand Up @@ -101,7 +102,7 @@ Use these commands to recover, update, pause, or remove an installation:

```sh
void platform discover [--account <id>] [--installation <id-or-name>]
void platform upgrade [id] [--runtime <path>] [--dashboard-url <origin>] [--custom-domains] [--plan] [--yes]
void platform upgrade [id] [--runtime <path>] [--dashboard-url <origin>] [--custom-domains] [--runtime-logs <full|minimal>] [--plan] [--yes]
void platform rollback [id] --runtime <earlier-path> [--from-runtime <current-path>] [--plan] [--yes]
void platform repair [id] [--runtime <path>] [--dashboard-url <origin>] [--custom-domains] [--auth-config <path>] [--plan] [--yes]
void platform disable [id] [--plan] [--yes]
Expand All @@ -113,6 +114,8 @@ void platform uninstall [id] [--plan] [--purge-data | --purge-resources] [--yes]

Use the installation slug shown beside its name in `void platform list`. Installation IDs and saved connection IDs also work. Lifecycle commands require local installation records; use `discover` to restore them on another machine. Omit `id` when only one installation is configured, or choose from the interactive picker. Non-interactive commands need a slug or ID when several installations exist. Commands that make changes also require `--yes`; `--plan` only previews changes.

`upgrade --runtime-logs <full|minimal>` changes what runtime logs record; without it, upgrades keep the current setting. See [Choose what runtime logs record](../../guide/platform/installation/setup.md#runtime-logs).

To add or explicitly change a separately deployed dashboard after installation,
use `repair --dashboard-url <origin>` or `upgrade --dashboard-url <origin>`.
Preview with `--plan` first. Existing Access protection must cover the configured
Expand Down
1 change: 1 addition & 0 deletions packages/platform/scripts/build-runtime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ try {
authenticationProtocolVersion: 1,
deploymentExecution: 1,
appAccessSetup: 1,
runtimeLogs: 1,
emailProtocolVersion: 1,
database,
platformVersion: packageJson.version,
Expand Down
1 change: 1 addition & 0 deletions packages/platform/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export {
type PlatformDeploymentManifest,
type PlatformDeploymentManifestInput,
type PlatformResourceNames,
type PlatformRuntimeLogs,
} from './manifest.ts';
export {
PLATFORM_DISABLED_KEY,
Expand Down
6 changes: 6 additions & 0 deletions packages/platform/src/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export type PlatformRuntimeDatabaseManifest = Readonly<{

export type PlatformRuntimeManifest = Readonly<{
appAccessSetup?: 1;
/** The runtime honours `runtimeLogs: minimal` (PLATFORM_RUNTIME_LOGS). */
runtimeLogs?: 1;
/** Durable deployment Queue payload and PostgreSQL operation journal contract. */
deploymentExecution?: 1;
authenticationProtocolVersion?: 1;
Expand Down Expand Up @@ -105,6 +107,9 @@ export function parsePlatformRuntimeManifest(value: unknown): PlatformRuntimeMan
if (root.appAccessSetup !== undefined && root.appAccessSetup !== 1) {
throw new Error('Unsupported app access setup protocol.');
}
if (root.runtimeLogs !== undefined && root.runtimeLogs !== 1) {
throw new Error('Unsupported runtime logs protocol.');
}
if (root.deploymentExecution !== undefined && root.deploymentExecution !== 1) {
throw new Error('Unsupported deployment execution protocol.');
}
Expand Down Expand Up @@ -224,6 +229,7 @@ export function parsePlatformRuntimeManifest(value: unknown): PlatformRuntimeMan
return {
artifacts,
...(root.appAccessSetup === 1 ? { appAccessSetup: 1 as const } : {}),
...(root.runtimeLogs === 1 ? { runtimeLogs: 1 as const } : {}),
...(root.deploymentExecution === 1 ? { deploymentExecution: 1 as const } : {}),
...(assets ? { assets } : {}),
...(root.authenticationProtocolVersion === 1
Expand Down
49 changes: 35 additions & 14 deletions packages/platform/src/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ export type PlatformResourceNames = Readonly<{

export type PlatformAppAccess = 'public' | 'platform' | 'custom';

/**
* `minimal` keeps request URLs, console messages and exception messages out of
* Workers Logs and the platform's request log rows. Omitted means `full`.
*/
export type PlatformRuntimeLogs = 'minimal';

export type PlatformDeploymentManifest = Readonly<{
/** Initial app-access choice. Omitted on installations created before guided setup. */
appAccess?: PlatformAppAccess;
Expand All @@ -64,7 +70,9 @@ export type PlatformDeploymentManifest = Readonly<{
displayName: string;
installationSlug: string;
resources: PlatformResourceNames;
schemaVersion: typeof PLATFORM_DEPLOYMENT_SCHEMA_VERSION | 2 | 3 | 4;
/** Requires schema version 5, so an older CLI refuses the manifest instead of dropping it. */
runtimeLogs?: PlatformRuntimeLogs;
schemaVersion: typeof PLATFORM_DEPLOYMENT_SCHEMA_VERSION | 2 | 3 | 4 | 5;
}>;

export type PlatformDeploymentManifestInput = Readonly<{
Expand All @@ -88,6 +96,7 @@ export type PlatformDeploymentManifestInput = Readonly<{
displayName: string;
installationSlug: string;
resources?: Partial<PlatformResourceNames>;
runtimeLogs?: PlatformRuntimeLogs;
}>;

export type PlatformApplicationRoute = Readonly<{
Expand Down Expand Up @@ -267,6 +276,9 @@ export function createPlatformDeploymentManifest(
) {
throw new Error('appAccess must be public, platform, or custom.');
}
if (input.runtimeLogs !== undefined && input.runtimeLogs !== 'minimal') {
throw new Error('runtimeLogs must be minimal when set.');
}
const providers = input.authentication?.providers ?? ['github'];
if (
providers.some((provider) => !PLATFORM_LOGIN_KINDS.includes(provider)) ||
Expand Down Expand Up @@ -328,8 +340,10 @@ export function createPlatformDeploymentManifest(
displayName: requiredString(input.displayName, 'displayName').trim(),
installationSlug,
resources,
schemaVersion:
input.appAccess !== undefined
...(input.runtimeLogs ? { runtimeLogs: input.runtimeLogs } : {}),
schemaVersion: input.runtimeLogs
? 5
: input.appAccess !== undefined
? 4
: configurable
? 3
Expand Down Expand Up @@ -364,7 +378,8 @@ export function parsePlatformDeploymentManifest(value: unknown): PlatformDeploym
value.schemaVersion !== PLATFORM_DEPLOYMENT_SCHEMA_VERSION &&
value.schemaVersion !== 2 &&
value.schemaVersion !== 3 &&
value.schemaVersion !== 4
value.schemaVersion !== 4 &&
value.schemaVersion !== 5
) {
throw new Error(
`Unsupported platform deployment schema version: ${String(value.schemaVersion)}.`,
Expand All @@ -379,8 +394,7 @@ export function parsePlatformDeploymentManifest(value: unknown): PlatformDeploym
let workersDev: PlatformApplication['workersDev'];
if (
value.schemaVersion === 2 ||
((value.schemaVersion === 3 || value.schemaVersion === 4) &&
application.workersDev !== undefined)
(Number(value.schemaVersion) >= 3 && application.workersDev !== undefined)
) {
assertRecord(application.workersDev, 'application.workersDev');
workersDev = {
Expand Down Expand Up @@ -412,18 +426,14 @@ export function parsePlatformDeploymentManifest(value: unknown): PlatformDeploym
providers.some(
(provider) =>
!PLATFORM_LOGIN_KINDS.includes(provider as PlatformLoginKind) ||
(value.schemaVersion !== 3 &&
value.schemaVersion !== 4 &&
provider !== 'github' &&
provider !== 'google'),
(Number(value.schemaVersion) < 3 && provider !== 'github' && provider !== 'google'),
)
) {
throw new Error('authentication.providers must contain only github or google.');
}
if (
(value.schemaVersion === 3 && authentication.configurable !== true) ||
(value.schemaVersion !== 3 &&
value.schemaVersion !== 4 &&
(Number(value.schemaVersion) < 3 &&
(authentication.configurable !== undefined ||
authentication.accessProtection !== undefined)) ||
(authentication.accessProtection !== undefined && authentication.accessProtection !== true)
Expand All @@ -433,7 +443,10 @@ export function parsePlatformDeploymentManifest(value: unknown): PlatformDeploym
if (
value.schemaVersion === 4
? !['public', 'platform', 'custom'].includes(String(value.appAccess))
: value.appAccess !== undefined
: value.schemaVersion === 5
? value.appAccess !== undefined &&
!['public', 'platform', 'custom'].includes(String(value.appAccess))
: value.appAccess !== undefined
) {
throw new Error(
'Guided app access requires deployment schema version 4 and a valid appAccess choice.',
Expand All @@ -442,6 +455,11 @@ export function parsePlatformDeploymentManifest(value: unknown): PlatformDeploym
if (authentication.configurable !== undefined && authentication.configurable !== true) {
throw new Error('Invalid configurable authentication flag.');
}
if (
value.schemaVersion === 5 ? value.runtimeLogs !== 'minimal' : value.runtimeLogs !== undefined
) {
throw new Error('Minimal runtime logs require deployment schema version 5.');
}
const resourceDefaults = createPlatformResourceNames(
requiredString(value.installationSlug, 'installationSlug'),
);
Expand All @@ -462,7 +480,9 @@ export function parsePlatformDeploymentManifest(value: unknown): PlatformDeploym
return hostname === null ? null : requiredString(hostname, `controlPlane.${key}`);
};
return createPlatformDeploymentManifest({
...(value.schemaVersion === 4 ? { appAccess: value.appAccess as PlatformAppAccess } : {}),
...(Number(value.schemaVersion) >= 4 && value.appAccess !== undefined
? { appAccess: value.appAccess as PlatformAppAccess }
: {}),
application: {
baseDomain: requiredString(application.baseDomain, 'application.baseDomain'),
dedicatedZone: application.dedicatedZone === true,
Expand Down Expand Up @@ -496,5 +516,6 @@ export function parsePlatformDeploymentManifest(value: unknown): PlatformDeploym
displayName: requiredString(value.displayName, 'displayName'),
installationSlug: requiredString(value.installationSlug, 'installationSlug'),
resources,
...(value.schemaVersion === 5 ? { runtimeLogs: 'minimal' as const } : {}),
});
}
10 changes: 9 additions & 1 deletion packages/platform/src/worker-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,15 @@ export function createPlatformWorkerConfigs(input: {
}),
),
});
// Sent only in minimal mode, so default Worker configs stay unchanged.
const runtimeLogs = deployment.runtimeLogs
? { PLATFORM_RUNTIME_LOGS: deployment.runtimeLogs }
: {};
const common = {
account_id: accountId,
compatibility_date: '2026-02-24',
observability: { enabled: true },
// Minimal runtime logs keep Workers Logs off on every platform Worker.
observability: { enabled: !deployment.runtimeLogs },
preview_urls: publicEndpoints && !deployment.authentication.accessProtection,
workers_dev: publicEndpoints,
};
Expand Down Expand Up @@ -201,6 +206,7 @@ export function createPlatformWorkerConfigs(input: {
PLATFORM_HEALTH_PROBE_TOKEN: healthProbeToken,
...(deployment.appAccess ? { PLATFORM_APP_ACCESS: deployment.appAccess } : {}),
PLATFORM_INSTALLATION_ID: installationId,
...runtimeLogs,
PLATFORM_TRAFFIC_STATE: trafficState,
...ownershipVars('api-worker', names.apiWorker),
PLATFORM_VERSION: platformVersion,
Expand Down Expand Up @@ -287,6 +293,7 @@ export function createPlatformWorkerConfigs(input: {
analytics_engine_datasets: [{ binding: 'ANALYTICS', dataset: names.logsDataset }],
vars: {
PLATFORM_DISPATCH_WORKER_NAME: names.dispatchWorker,
...runtimeLogs,
...ownershipVars('tail-worker', names.tailWorker),
},
},
Expand Down Expand Up @@ -323,6 +330,7 @@ export function createPlatformWorkerConfigs(input: {
PLATFORM_HEALTH_PROBE_TOKEN: healthProbeToken,
PLATFORM_INSTALLATION_ID: installationId,
PLATFORM_TRAFFIC_STATE: trafficState,
...runtimeLogs,
...ownershipVars('dispatch-worker', names.dispatchWorker),
},
},
Expand Down
Loading
Loading