@void/platform 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -4
- package/dist/index.d.mts +21 -2
- package/dist/index.mjs +52 -7
- package/dist/installer.d.mts +1 -0
- package/dist/installer.mjs +2 -0
- package/dist/runtime/api/README.md +1 -1
- package/dist/runtime/api/assets/admin/client.js +1 -1
- package/dist/runtime/api/index.js +561 -84
- package/dist/runtime/api/index.js.map +4 -4
- package/dist/runtime/dispatch/README.md +1 -1
- package/dist/runtime/dispatch/index.js +7 -1
- package/dist/runtime/dispatch/index.js.map +2 -2
- package/dist/runtime/emailGateway/README.md +1 -1
- package/dist/runtime/manifest.json +9 -8
- package/dist/runtime/proxy/README.md +1 -1
- package/dist/runtime/tail/README.md +1 -1
- package/package.json +1 -1
|
@@ -556,6 +556,30 @@ var init_plans = __esm({
|
|
|
556
556
|
});
|
|
557
557
|
|
|
558
558
|
// ../../home/runner/work/void/void/packages/platform/dist/index.mjs
|
|
559
|
+
function parsePlatformAppAccessSetup(value) {
|
|
560
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Invalid app access setup.");
|
|
561
|
+
const input2 = value;
|
|
562
|
+
if (input2.version !== 1 || !["public", "protected"].includes(String(input2.mode)) || typeof input2.managed !== "boolean" || typeof input2.accountId !== "string" || !input2.accountId) throw new Error("Invalid app access setup.");
|
|
563
|
+
const ids2 = /* @__PURE__ */ __name((name) => {
|
|
564
|
+
const entries2 = input2[name];
|
|
565
|
+
if (!Array.isArray(entries2) || entries2.length > 16 || entries2.some((id2) => typeof id2 !== "string" || !id2.trim() || id2.length > 128) || new Set(entries2).size !== entries2.length) throw new Error(`Invalid app access ${name}.`);
|
|
566
|
+
return [...entries2];
|
|
567
|
+
}, "ids");
|
|
568
|
+
const identityProviderIds = ids2("identityProviderIds");
|
|
569
|
+
const policyIds = ids2("policyIds");
|
|
570
|
+
if (input2.mode === "protected" && (!input2.managed || !identityProviderIds.length || !policyIds.length)) throw new Error("Protected apps require identity providers, policies, and an Access-management token.");
|
|
571
|
+
if (input2.mode === "public" && (identityProviderIds.length || policyIds.length)) throw new Error("Public app access cannot include identity policies.");
|
|
572
|
+
if (input2.managed ? typeof input2.apiToken !== "string" || !input2.apiToken.trim() || /\s/.test(input2.apiToken) || input2.apiToken.length > 8192 : input2.apiToken !== void 0) throw new Error("Managed app access requires a token; unmanaged public access must not retain one.");
|
|
573
|
+
return {
|
|
574
|
+
version: 1,
|
|
575
|
+
accountId: input2.accountId,
|
|
576
|
+
mode: input2.mode,
|
|
577
|
+
managed: input2.managed,
|
|
578
|
+
...input2.managed ? { apiToken: input2.apiToken } : {},
|
|
579
|
+
identityProviderIds,
|
|
580
|
+
policyIds
|
|
581
|
+
};
|
|
582
|
+
}
|
|
559
583
|
function platformAuthenticationRecoveryMessage(value) {
|
|
560
584
|
return JSON.stringify([
|
|
561
585
|
"void-platform-auth-recovery-v1",
|
|
@@ -854,6 +878,11 @@ function createPlatformDeploymentManifest(input2) {
|
|
|
854
878
|
...input2.capabilities
|
|
855
879
|
};
|
|
856
880
|
if (capabilities.managedBuilds && !capabilities.githubActions) throw new Error("Managed builds require the GitHub Actions capability.");
|
|
881
|
+
if (input2.appAccess !== void 0 && ![
|
|
882
|
+
"public",
|
|
883
|
+
"platform",
|
|
884
|
+
"custom"
|
|
885
|
+
].includes(input2.appAccess)) throw new Error("appAccess must be public, platform, or custom.");
|
|
857
886
|
const providers2 = input2.authentication?.providers ?? ["github"];
|
|
858
887
|
if (providers2.some((provider) => !PLATFORM_LOGIN_KINDS.includes(provider)) || new Set(providers2).size !== providers2.length) throw new Error("Authentication providers must be unique supported login kinds.");
|
|
859
888
|
const configurable = input2.authentication?.configurable === true || input2.authentication?.accessProtection === true || providers2.some((provider) => provider === "oidc" || provider === "cloudflare-access");
|
|
@@ -862,6 +891,7 @@ function createPlatformDeploymentManifest(input2) {
|
|
|
862
891
|
if (providers2.includes("google") !== capabilities.googleOAuth) throw new Error("The Google provider and googleOAuth capability must agree.");
|
|
863
892
|
const dashboardUrl = input2.controlPlane?.dashboardUrl === void 0 ? void 0 : normalizePlatformDashboardUrl(input2.controlPlane.dashboardUrl);
|
|
864
893
|
const manifest = {
|
|
894
|
+
...input2.appAccess !== void 0 ? { appAccess: input2.appAccess } : {},
|
|
865
895
|
application: {
|
|
866
896
|
baseDomain,
|
|
867
897
|
dedicatedZone: input2.application.dedicatedZone ?? false,
|
|
@@ -888,7 +918,7 @@ function createPlatformDeploymentManifest(input2) {
|
|
|
888
918
|
displayName: requiredString$1(input2.displayName, "displayName").trim(),
|
|
889
919
|
installationSlug,
|
|
890
920
|
resources: resources2,
|
|
891
|
-
schemaVersion: configurable ? 3 : workersDev ? 2 : 1
|
|
921
|
+
schemaVersion: input2.appAccess !== void 0 ? 4 : configurable ? 3 : workersDev ? 2 : 1
|
|
892
922
|
};
|
|
893
923
|
createApplicationRoutes(manifest.application);
|
|
894
924
|
for (const [key, value] of Object.entries(manifest.controlPlane)) {
|
|
@@ -1008,12 +1038,14 @@ function parseAuthentication(value) {
|
|
|
1008
1038
|
...authentication.setupPending === true ? { setupPending: true } : {}
|
|
1009
1039
|
};
|
|
1010
1040
|
}
|
|
1011
|
-
var PLATFORM_LOGIN_KINDS, GOOGLE_OIDC_ISSUER, PLATFORM_AUTH_SETUP_PROOF_PREFIX, CORE_CAPABILITIES, CONTROL_PLANE_DEFAULTS, PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE, PLATFORM_USAGE_PROTOCOL_VERSION, PLATFORM_PROJECT_INGRESS_SOURCE, PLATFORM_APPLICATION_KEY, PLATFORM_HEALTH_HOSTNAME_LABEL;
|
|
1041
|
+
var PLATFORM_APP_ACCESS_SETUP_PROOF_PREFIX, PLATFORM_LOGIN_KINDS, GOOGLE_OIDC_ISSUER, PLATFORM_AUTH_SETUP_PROOF_PREFIX, CORE_CAPABILITIES, CONTROL_PLANE_DEFAULTS, PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE, PLATFORM_USAGE_PROTOCOL_VERSION, PLATFORM_PROJECT_INGRESS_SOURCE, PLATFORM_APPLICATION_KEY, PLATFORM_HEALTH_HOSTNAME_LABEL;
|
|
1012
1042
|
var init_dist = __esm({
|
|
1013
1043
|
"../../home/runner/work/void/void/packages/platform/dist/index.mjs"() {
|
|
1014
1044
|
"use strict";
|
|
1015
1045
|
init_performance2();
|
|
1016
1046
|
init_plans();
|
|
1047
|
+
PLATFORM_APP_ACCESS_SETUP_PROOF_PREFIX = "void-platform-app-access-v1";
|
|
1048
|
+
__name(parsePlatformAppAccessSetup, "parsePlatformAppAccessSetup");
|
|
1017
1049
|
__name(platformAuthenticationRecoveryMessage, "platformAuthenticationRecoveryMessage");
|
|
1018
1050
|
PLATFORM_LOGIN_KINDS = [
|
|
1019
1051
|
"github",
|
|
@@ -30326,24 +30358,46 @@ __export(cloudflare_api_exports, {
|
|
|
30326
30358
|
updateHyperdrive: () => updateHyperdrive
|
|
30327
30359
|
});
|
|
30328
30360
|
async function cfFetch(url2, apiToken, init) {
|
|
30329
|
-
const
|
|
30330
|
-
|
|
30331
|
-
|
|
30332
|
-
|
|
30333
|
-
|
|
30334
|
-
|
|
30335
|
-
|
|
30336
|
-
|
|
30337
|
-
const json3 = await response.json();
|
|
30338
|
-
if (!json3.success) {
|
|
30339
|
-
const message2 = json3.errors.map((error63) => error63.message).join(", ");
|
|
30340
|
-
throw new CloudflareApiError(
|
|
30341
|
-
`Cloudflare API error: ${message2}`,
|
|
30342
|
-
response.status,
|
|
30343
|
-
json3.errors.map((error63) => error63.code)
|
|
30361
|
+
const deadline = new AbortController();
|
|
30362
|
+
const method = init?.method ?? "GET";
|
|
30363
|
+
const pathname = new URL(url2).pathname;
|
|
30364
|
+
const timer = setTimeout(() => {
|
|
30365
|
+
deadline.abort(
|
|
30366
|
+
new Error(
|
|
30367
|
+
`Cloudflare API request timed out after 60 seconds: ${method} ${pathname}.` + (method === "GET" || method === "HEAD" ? "" : " The write may have succeeded; inspect its state before retrying.")
|
|
30368
|
+
)
|
|
30344
30369
|
);
|
|
30370
|
+
}, 6e4);
|
|
30371
|
+
const signal2 = init?.signal ? AbortSignal.any([init.signal, deadline.signal]) : deadline.signal;
|
|
30372
|
+
try {
|
|
30373
|
+
signal2.throwIfAborted();
|
|
30374
|
+
const response = await fetch(url2, {
|
|
30375
|
+
...init,
|
|
30376
|
+
signal: signal2,
|
|
30377
|
+
headers: {
|
|
30378
|
+
Authorization: `Bearer ${apiToken}`,
|
|
30379
|
+
"Content-Type": "application/json",
|
|
30380
|
+
...init?.headers
|
|
30381
|
+
}
|
|
30382
|
+
});
|
|
30383
|
+
const json3 = await response.json();
|
|
30384
|
+
if (!json3.success) {
|
|
30385
|
+
const message2 = json3.errors.map((error63) => error63.message).join(", ");
|
|
30386
|
+
throw new CloudflareApiError(
|
|
30387
|
+
`Cloudflare API error: ${message2}`,
|
|
30388
|
+
response.status,
|
|
30389
|
+
json3.errors.map((error63) => error63.code)
|
|
30390
|
+
);
|
|
30391
|
+
}
|
|
30392
|
+
return json3.result;
|
|
30393
|
+
} catch (error63) {
|
|
30394
|
+
if (deadline.signal.aborted && !init?.signal?.aborted) {
|
|
30395
|
+
throw deadline.signal.reason;
|
|
30396
|
+
}
|
|
30397
|
+
throw error63;
|
|
30398
|
+
} finally {
|
|
30399
|
+
clearTimeout(timer);
|
|
30345
30400
|
}
|
|
30346
|
-
return json3.result;
|
|
30347
30401
|
}
|
|
30348
30402
|
async function createD1Database(accountId, apiToken, name) {
|
|
30349
30403
|
return cfFetch(`${CF_API_BASE}/${accountId}/d1/database`, apiToken, {
|
|
@@ -51729,10 +51783,10 @@ function cloudDomainFromHost(host) {
|
|
|
51729
51783
|
function systemHealthCheckNames(installed) {
|
|
51730
51784
|
return ["api", "proxy", ...installed ? [] : ["dashboard"], "dispatch", "db"];
|
|
51731
51785
|
}
|
|
51732
|
-
async function checkUrl(name, url2, headers) {
|
|
51786
|
+
async function checkUrl(name, url2, headers, request = fetch) {
|
|
51733
51787
|
const start = Date.now();
|
|
51734
51788
|
try {
|
|
51735
|
-
const res = await
|
|
51789
|
+
const res = await request(url2, {
|
|
51736
51790
|
headers,
|
|
51737
51791
|
// Do not forward probe credentials to a login redirect or treat its HTML
|
|
51738
51792
|
// login page as a successful health check.
|
|
@@ -51837,7 +51891,8 @@ async function systemHealth(db, env2, requestUrl) {
|
|
|
51837
51891
|
checkUrl(
|
|
51838
51892
|
"proxy",
|
|
51839
51893
|
`${proxyUrl.replace(/\/$/, "")}/health`,
|
|
51840
|
-
installed ? dispatchHeaders : void 0
|
|
51894
|
+
installed ? dispatchHeaders : void 0,
|
|
51895
|
+
installed && env2.PLATFORM_PROXY ? (url2, init) => env2.PLATFORM_PROXY.fetch(url2, init) : void 0
|
|
51841
51896
|
),
|
|
51842
51897
|
...!installed ? [
|
|
51843
51898
|
checkUrl(
|
|
@@ -57083,6 +57138,27 @@ function healthCheckApplication(name, hostname3) {
|
|
|
57083
57138
|
policies: bypassPolicy("Void platform health check")
|
|
57084
57139
|
};
|
|
57085
57140
|
}
|
|
57141
|
+
function publicAppManagementDestination(apiUrl) {
|
|
57142
|
+
const url2 = new URL(apiUrl);
|
|
57143
|
+
if (url2.protocol !== "https:" || url2.username || url2.password) {
|
|
57144
|
+
throw new Error("Public app management requires an HTTPS dispatch origin.");
|
|
57145
|
+
}
|
|
57146
|
+
return url2.host + "/__void/app-access-management";
|
|
57147
|
+
}
|
|
57148
|
+
function publicAppManagementApplication(name, destination) {
|
|
57149
|
+
return {
|
|
57150
|
+
name,
|
|
57151
|
+
destinations: [destination],
|
|
57152
|
+
policies: [
|
|
57153
|
+
{
|
|
57154
|
+
name: "App access management check",
|
|
57155
|
+
decision: "deny",
|
|
57156
|
+
precedence: 1,
|
|
57157
|
+
include: [{ everyone: {} }]
|
|
57158
|
+
}
|
|
57159
|
+
]
|
|
57160
|
+
};
|
|
57161
|
+
}
|
|
57086
57162
|
var ZeroTrustCloudflareError, ZeroTrustCloudflareClient;
|
|
57087
57163
|
var init_cloudflare = __esm({
|
|
57088
57164
|
"../../home/runner/work/void/void/platform/packages/api/src/zero-trust/cloudflare.ts"() {
|
|
@@ -57398,6 +57474,78 @@ var init_cloudflare = __esm({
|
|
|
57398
57474
|
throw error63;
|
|
57399
57475
|
}
|
|
57400
57476
|
}
|
|
57477
|
+
/** An installer/operator-owned health exception is verified, never modified or adopted. */
|
|
57478
|
+
async verifyExistingHealthApplication(application, hostname3, current) {
|
|
57479
|
+
const id2 = text2(application.id, "application id");
|
|
57480
|
+
const name = text2(application.name, "application name");
|
|
57481
|
+
const audience = text2(application.aud, "application audience");
|
|
57482
|
+
const destination = `${hostname3}/health`;
|
|
57483
|
+
if (current && (id2 !== current.id || name !== current.name || audience !== current.audience) || application.type !== "self_hosted" || application.domain !== destination || !sameDestinations(application, [destination]) || application.destinations !== void 0 && (!Array.isArray(application.destinations) || application.destinations.some((entry) => {
|
|
57484
|
+
const value = object3(entry, "Access application destination");
|
|
57485
|
+
return value.type !== "public" || value.uri !== destination;
|
|
57486
|
+
})) || application.target_criteria != null && (!Array.isArray(application.target_criteria) || application.target_criteria.length > 0)) {
|
|
57487
|
+
throw new Error(
|
|
57488
|
+
`The existing Access health application must cover only ${destination} and retain its recorded identity.`
|
|
57489
|
+
);
|
|
57490
|
+
}
|
|
57491
|
+
const policies = await this.request(
|
|
57492
|
+
`apps/${encodeURIComponent(id2)}/policies?page=1&per_page=2`
|
|
57493
|
+
);
|
|
57494
|
+
const policy = policies?.[0];
|
|
57495
|
+
if (!Array.isArray(policies) || policies.length !== 1 || policy?.decision !== "bypass" || JSON.stringify(policy.include) !== '[{"everyone":{}}]' || policy.require !== void 0 && (!Array.isArray(policy.require) || policy.require.length > 0) || policy.exclude !== void 0 && (!Array.isArray(policy.exclude) || policy.exclude.length > 0)) {
|
|
57496
|
+
throw new Error(
|
|
57497
|
+
`The existing Access policy for ${destination} must remain the reserved health-check exception.`
|
|
57498
|
+
);
|
|
57499
|
+
}
|
|
57500
|
+
return { id: id2, name, audience, destinations: [destination] };
|
|
57501
|
+
}
|
|
57502
|
+
async ensureHealthApplication(name, hostname3, current) {
|
|
57503
|
+
if (current && current.name !== name) {
|
|
57504
|
+
const application2 = await this.application(current.id);
|
|
57505
|
+
if (!application2) {
|
|
57506
|
+
throw new Error(
|
|
57507
|
+
"The existing Access health application is missing. Restore it before reconciling project Zero Trust."
|
|
57508
|
+
);
|
|
57509
|
+
}
|
|
57510
|
+
return this.verifyExistingHealthApplication(application2, hostname3, current);
|
|
57511
|
+
}
|
|
57512
|
+
const { application, inventory } = await this.locateOwnedApplication(current?.id, name);
|
|
57513
|
+
if (application) {
|
|
57514
|
+
return this.ensureApplication(healthCheckApplication(name, hostname3), {
|
|
57515
|
+
id: text2(application.id, "application id"),
|
|
57516
|
+
name
|
|
57517
|
+
});
|
|
57518
|
+
}
|
|
57519
|
+
const matches = [...inventory.values()].filter(
|
|
57520
|
+
(entry) => destinationList(entry).includes(`${hostname3}/health`)
|
|
57521
|
+
);
|
|
57522
|
+
if (matches.length > 1) {
|
|
57523
|
+
throw new Error(
|
|
57524
|
+
`Multiple Access applications cover ${hostname3}/health. Reconcile them before retrying.`
|
|
57525
|
+
);
|
|
57526
|
+
}
|
|
57527
|
+
if (matches[0]) {
|
|
57528
|
+
const existing = await this.application(text2(matches[0].id, "application id"));
|
|
57529
|
+
if (!existing) {
|
|
57530
|
+
throw new Error(
|
|
57531
|
+
"The existing Access health application disappeared. Inspect Access before retrying."
|
|
57532
|
+
);
|
|
57533
|
+
}
|
|
57534
|
+
return this.verifyExistingHealthApplication(existing, hostname3);
|
|
57535
|
+
}
|
|
57536
|
+
return this.ensureApplication(healthCheckApplication(name, hostname3), { name });
|
|
57537
|
+
}
|
|
57538
|
+
async inspectHealthApplication(current, managedName, hostname3) {
|
|
57539
|
+
if (current.name === managedName) {
|
|
57540
|
+
return this.inspectApplication(current, healthCheckApplication(current.name, hostname3));
|
|
57541
|
+
}
|
|
57542
|
+
const application = await this.application(current.id);
|
|
57543
|
+
if (!application) {
|
|
57544
|
+
return { present: false, drifted: true };
|
|
57545
|
+
}
|
|
57546
|
+
await this.verifyExistingHealthApplication(application, hostname3, current);
|
|
57547
|
+
return { present: true, drifted: false };
|
|
57548
|
+
}
|
|
57401
57549
|
async deleteApplication(id2, expectedName) {
|
|
57402
57550
|
if (!id2 && !expectedName) {
|
|
57403
57551
|
return;
|
|
@@ -57419,6 +57567,8 @@ var init_cloudflare = __esm({
|
|
|
57419
57567
|
__name(reusablePolicyReferences, "reusablePolicyReferences");
|
|
57420
57568
|
__name(bypassPolicy, "bypassPolicy");
|
|
57421
57569
|
__name(healthCheckApplication, "healthCheckApplication");
|
|
57570
|
+
__name(publicAppManagementDestination, "publicAppManagementDestination");
|
|
57571
|
+
__name(publicAppManagementApplication, "publicAppManagementApplication");
|
|
57422
57572
|
}
|
|
57423
57573
|
});
|
|
57424
57574
|
|
|
@@ -57465,8 +57615,8 @@ function timestamp2(value, label) {
|
|
|
57465
57615
|
}
|
|
57466
57616
|
return result;
|
|
57467
57617
|
}
|
|
57468
|
-
function ids(value, label) {
|
|
57469
|
-
if (!Array.isArray(value) || value.length <
|
|
57618
|
+
function ids(value, label, minimum = 1) {
|
|
57619
|
+
if (!Array.isArray(value) || value.length < minimum || value.length > 16) {
|
|
57470
57620
|
throw new ZeroTrustConfigurationError(`${label} must contain between 1 and 16 ids`);
|
|
57471
57621
|
}
|
|
57472
57622
|
const result = value.map((entry) => requiredText(entry, `${label} id`, 128));
|
|
@@ -57588,6 +57738,9 @@ function parseZeroTrustConfiguration(value) {
|
|
|
57588
57738
|
if (typeof input2.enabled !== "boolean" || typeof input2.protectNewProjects !== "boolean") {
|
|
57589
57739
|
throw new ZeroTrustConfigurationError("Zero Trust configuration flags are invalid");
|
|
57590
57740
|
}
|
|
57741
|
+
if (input2.publicAccess !== void 0 && input2.publicAccess !== true || input2.managePublicCustomDomains !== void 0 && input2.managePublicCustomDomains !== true || input2.publicAccess && input2.protectNewProjects) {
|
|
57742
|
+
throw new ZeroTrustConfigurationError("invalid public app access configuration");
|
|
57743
|
+
}
|
|
57591
57744
|
const teamDomain = requiredText(input2.teamDomain, "Access team domain", 512).replace(/\/+$/, "");
|
|
57592
57745
|
let parsedTeamDomain;
|
|
57593
57746
|
try {
|
|
@@ -57602,9 +57755,29 @@ function parseZeroTrustConfiguration(value) {
|
|
|
57602
57755
|
"Access team domain must be an HTTPS cloudflareaccess.com origin"
|
|
57603
57756
|
);
|
|
57604
57757
|
}
|
|
57758
|
+
let publicAccessGuardDestination;
|
|
57759
|
+
if (input2.publicAccess) {
|
|
57760
|
+
publicAccessGuardDestination = requiredText(
|
|
57761
|
+
input2.publicAccessGuardDestination,
|
|
57762
|
+
"public app management destination",
|
|
57763
|
+
512
|
|
57764
|
+
);
|
|
57765
|
+
try {
|
|
57766
|
+
if (publicAppManagementDestination("https://" + publicAccessGuardDestination) !== publicAccessGuardDestination) {
|
|
57767
|
+
throw new Error("invalid destination");
|
|
57768
|
+
}
|
|
57769
|
+
} catch {
|
|
57770
|
+
throw new ZeroTrustConfigurationError("Invalid public app management destination");
|
|
57771
|
+
}
|
|
57772
|
+
}
|
|
57605
57773
|
const wildcardApplication = parseApplication(input2.wildcardApplication);
|
|
57606
57774
|
const healthApplication = parseApplication(input2.healthApplication ?? null);
|
|
57607
57775
|
const operation = parseOperation(input2.operation);
|
|
57776
|
+
if (input2.publicAccess && (operation?.existingProjects === "protected" || Array.isArray(input2.identityProviderIds) && input2.identityProviderIds.length > 0 || Array.isArray(input2.policyIds) && input2.policyIds.length > 0)) {
|
|
57777
|
+
throw new ZeroTrustConfigurationError(
|
|
57778
|
+
"Public app access cannot contain identity policies or protected project choices"
|
|
57779
|
+
);
|
|
57780
|
+
}
|
|
57608
57781
|
if (operation?.phase === "bypass-delete" && (input2.enabled || wildcardApplication)) {
|
|
57609
57782
|
throw new ZeroTrustConfigurationError("Zero Trust bypass cleanup requires wildcard removal");
|
|
57610
57783
|
}
|
|
@@ -57620,8 +57793,14 @@ function parseZeroTrustConfiguration(value) {
|
|
|
57620
57793
|
protectNewProjects: input2.protectNewProjects,
|
|
57621
57794
|
accountId: requiredText(input2.accountId, "Cloudflare account id", 128),
|
|
57622
57795
|
teamDomain,
|
|
57623
|
-
|
|
57624
|
-
|
|
57796
|
+
...input2.publicAccess === true ? { publicAccess: true, publicAccessGuardDestination } : {},
|
|
57797
|
+
...input2.managePublicCustomDomains === true ? { managePublicCustomDomains: true } : {},
|
|
57798
|
+
identityProviderIds: ids(
|
|
57799
|
+
input2.identityProviderIds,
|
|
57800
|
+
"identity providers",
|
|
57801
|
+
input2.publicAccess ? 0 : 1
|
|
57802
|
+
),
|
|
57803
|
+
policyIds: ids(input2.policyIds, "policies", input2.publicAccess ? 0 : 1),
|
|
57625
57804
|
credential: parseCredential(input2.credential),
|
|
57626
57805
|
wildcardApplicationName: requiredText(
|
|
57627
57806
|
input2.wildcardApplicationName,
|
|
@@ -57648,8 +57827,13 @@ function normalizeZeroTrustConfigureInput(input2) {
|
|
|
57648
57827
|
const apiToken = requiredText(value.apiToken, "Cloudflare API token", 8192);
|
|
57649
57828
|
return {
|
|
57650
57829
|
apiToken,
|
|
57651
|
-
|
|
57652
|
-
|
|
57830
|
+
...value.publicAccess === true ? { publicAccess: true, managePublicCustomDomains: true } : {},
|
|
57831
|
+
identityProviderIds: ids(
|
|
57832
|
+
value.identityProviderIds,
|
|
57833
|
+
"identity providers",
|
|
57834
|
+
value.publicAccess === true ? 0 : 1
|
|
57835
|
+
),
|
|
57836
|
+
policyIds: ids(value.policyIds, "policies", value.publicAccess === true ? 0 : 1),
|
|
57653
57837
|
protectNewProjects: value.protectNewProjects,
|
|
57654
57838
|
...existingProjects ? { existingProjects } : {}
|
|
57655
57839
|
};
|
|
@@ -57713,6 +57897,7 @@ var init_configuration2 = __esm({
|
|
|
57713
57897
|
init_drizzle_orm();
|
|
57714
57898
|
init_platform_settings();
|
|
57715
57899
|
init_schema2();
|
|
57900
|
+
init_cloudflare();
|
|
57716
57901
|
ZERO_TRUST_SETTING = "zeroTrust.configuration";
|
|
57717
57902
|
ZERO_TRUST_CREDENTIAL_ID = "zero-trust-cloudflare-api-token";
|
|
57718
57903
|
__name(zeroTrustConfigurationStatus, "zeroTrustConfigurationStatus");
|
|
@@ -57935,22 +58120,36 @@ async function updateProjectState(db, projectId, values2) {
|
|
|
57935
58120
|
}
|
|
57936
58121
|
return row;
|
|
57937
58122
|
}
|
|
57938
|
-
async function projectDestinations(env2, db, project2, protectedProject) {
|
|
58123
|
+
async function projectDestinations(env2, db, project2, protectedProject, verifiedDomainId) {
|
|
57939
58124
|
const application = readPlatformApplication(
|
|
57940
58125
|
await resolveZeroTrustApplicationEnvironment(env2, db)
|
|
57941
58126
|
);
|
|
57942
58127
|
const platform = [...new Set(platformProjectHostnames(project2, application))];
|
|
57943
|
-
|
|
58128
|
+
const reserved = [env2.AUTH_REDIRECT_URI, env2.PROXY_URL, env2.EMAIL_GATEWAY_ORIGIN].filter((value) => !!value && URL.canParse(value)).map((value) => new URL(value).hostname.toLowerCase());
|
|
58129
|
+
const checkHostnames = /* @__PURE__ */ __name((values2) => {
|
|
58130
|
+
if (values2.some((hostname3) => reserved.includes(hostname3.toLowerCase()))) {
|
|
58131
|
+
throw new ZeroTrustUnavailableError(
|
|
58132
|
+
"The project hostname overlaps a platform API, proxy, or email endpoint. Choose another hostname."
|
|
58133
|
+
);
|
|
58134
|
+
}
|
|
58135
|
+
}, "checkHostnames");
|
|
58136
|
+
checkHostnames(platform);
|
|
58137
|
+
if (!protectedProject && !(await readZeroTrustConfigurationStrict(db))?.managePublicCustomDomains) {
|
|
57944
58138
|
return { platform, custom: [] };
|
|
57945
58139
|
}
|
|
57946
58140
|
const custom2 = [
|
|
57947
|
-
...new Set(
|
|
58141
|
+
...new Set(
|
|
58142
|
+
(await getDomainsByProjectId(db, project2.id)).filter(
|
|
58143
|
+
(domain2) => protectedProject || domain2.status === "active" || domain2.id === verifiedDomainId
|
|
58144
|
+
).map((domain2) => domain2.hostname)
|
|
58145
|
+
)
|
|
57948
58146
|
];
|
|
57949
58147
|
if (custom2.length > MAX_ZERO_TRUST_CUSTOM_DOMAINS_PER_PROJECT) {
|
|
57950
58148
|
throw new ZeroTrustUnavailableError(
|
|
57951
58149
|
`Project Zero Trust supports at most ${MAX_ZERO_TRUST_CUSTOM_DOMAINS_PER_PROJECT} custom domains per project.`
|
|
57952
58150
|
);
|
|
57953
58151
|
}
|
|
58152
|
+
checkHostnames(custom2);
|
|
57954
58153
|
return { platform, custom: custom2 };
|
|
57955
58154
|
}
|
|
57956
58155
|
async function markProjectCustomDomainsChanged(db, projectId) {
|
|
@@ -58382,7 +58581,18 @@ async function checkpointProjectReconciliation(env2, db, projectId, options) {
|
|
|
58382
58581
|
}
|
|
58383
58582
|
const existing = await getProjectZeroTrustState(lockedDb, projectId);
|
|
58384
58583
|
const desired = options?.desiredProtection ?? existing?.desired_protected ?? initialProjectProtection(configuration, project2);
|
|
58385
|
-
|
|
58584
|
+
if (desired && configuration.publicAccess) {
|
|
58585
|
+
throw new ZeroTrustUnavailableError(
|
|
58586
|
+
"Choose company identity providers and policies in Admin \u2192 Zero Trust before protecting a project."
|
|
58587
|
+
);
|
|
58588
|
+
}
|
|
58589
|
+
const destinations = await projectDestinations(
|
|
58590
|
+
env2,
|
|
58591
|
+
lockedDb,
|
|
58592
|
+
project2,
|
|
58593
|
+
desired,
|
|
58594
|
+
options?.verifiedDomainId
|
|
58595
|
+
);
|
|
58386
58596
|
const values2 = {
|
|
58387
58597
|
desired_protected: desired,
|
|
58388
58598
|
status: "reconciling",
|
|
@@ -58392,13 +58602,13 @@ async function checkpointProjectReconciliation(env2, db, projectId, options) {
|
|
|
58392
58602
|
if (!desired && !existing?.bypass_application_name) {
|
|
58393
58603
|
values2.bypass_application_name = await applicationName(env2, `public-${project2.id}`);
|
|
58394
58604
|
}
|
|
58395
|
-
if (desired && destinations.custom.length > 0 && !existing?.protected_application_name) {
|
|
58605
|
+
if ((desired || configuration.managePublicCustomDomains) && destinations.custom.length > 0 && !existing?.protected_application_name) {
|
|
58396
58606
|
values2.protected_application_name = await applicationName(env2, `protected-${project2.id}`);
|
|
58397
58607
|
}
|
|
58398
58608
|
return putProjectState(lockedDb, projectId, values2);
|
|
58399
58609
|
});
|
|
58400
58610
|
}
|
|
58401
|
-
async function reconcilePublicProjectLocked(env2, lockedDb, project2, current, platformDestinations, client2, configuration, routingBudget) {
|
|
58611
|
+
async function reconcilePublicProjectLocked(env2, lockedDb, project2, current, platformDestinations, customDestinations, client2, configuration, routingBudget) {
|
|
58402
58612
|
if (!current.bypass_application_name) {
|
|
58403
58613
|
throw new Error("The project public application checkpoint is missing.");
|
|
58404
58614
|
}
|
|
@@ -58414,18 +58624,39 @@ async function reconcilePublicProjectLocked(env2, lockedDb, project2, current, p
|
|
|
58414
58624
|
bypass_application_id: bypass.id,
|
|
58415
58625
|
bypass_application_name: bypass.name
|
|
58416
58626
|
});
|
|
58627
|
+
let publicCustom = null;
|
|
58628
|
+
if (configuration.managePublicCustomDomains && customDestinations.length) {
|
|
58629
|
+
if (!current.protected_application_name) {
|
|
58630
|
+
throw new Error("The custom-domain Access checkpoint is missing.");
|
|
58631
|
+
}
|
|
58632
|
+
publicCustom = await client2.ensureApplication(
|
|
58633
|
+
{
|
|
58634
|
+
name: current.protected_application_name,
|
|
58635
|
+
destinations: customDestinations,
|
|
58636
|
+
policies: bypassPolicy("Void project is public")
|
|
58637
|
+
},
|
|
58638
|
+
projectApplicationReference(current, "protected")
|
|
58639
|
+
);
|
|
58640
|
+
await updateProjectState(lockedDb, project2.id, {
|
|
58641
|
+
protected_application_id: publicCustom.id,
|
|
58642
|
+
protected_application_name: publicCustom.name,
|
|
58643
|
+
protected_application_audience: publicCustom.audience
|
|
58644
|
+
});
|
|
58645
|
+
}
|
|
58417
58646
|
if (!await publishProjectZeroTrustRoutingLocked(env2, lockedDb, project2, null, routingBudget)) {
|
|
58418
58647
|
return await getProjectZeroTrustState(lockedDb, project2.id);
|
|
58419
58648
|
}
|
|
58420
58649
|
const row = await updateProjectState(lockedDb, project2.id, { effective_protected: false });
|
|
58421
|
-
|
|
58650
|
+
if (!publicCustom) {
|
|
58651
|
+
await client2.deleteApplication(row.protected_application_id, row.protected_application_name);
|
|
58652
|
+
}
|
|
58422
58653
|
return updateProjectState(lockedDb, project2.id, {
|
|
58423
58654
|
effective_protected: false,
|
|
58424
58655
|
status: "ready",
|
|
58425
58656
|
reconciled_operation: completedProjectOperation(configuration, true),
|
|
58426
|
-
protected_application_id: null,
|
|
58427
|
-
protected_application_name: null,
|
|
58428
|
-
protected_application_audience: null,
|
|
58657
|
+
protected_application_id: publicCustom?.id ?? null,
|
|
58658
|
+
protected_application_name: publicCustom?.name ?? null,
|
|
58659
|
+
protected_application_audience: publicCustom?.audience ?? null,
|
|
58429
58660
|
last_error: null
|
|
58430
58661
|
});
|
|
58431
58662
|
}
|
|
@@ -58448,7 +58679,8 @@ async function reconcileProjectZeroTrustLocked(env2, lockedDb, projectId, record
|
|
|
58448
58679
|
env2,
|
|
58449
58680
|
lockedDb,
|
|
58450
58681
|
project2,
|
|
58451
|
-
existing.desired_protected
|
|
58682
|
+
existing.desired_protected,
|
|
58683
|
+
options?.verifiedDomainId
|
|
58452
58684
|
);
|
|
58453
58685
|
return recordErrors(async () => {
|
|
58454
58686
|
let row = existing;
|
|
@@ -58459,6 +58691,7 @@ async function reconcileProjectZeroTrustLocked(env2, lockedDb, projectId, record
|
|
|
58459
58691
|
project2,
|
|
58460
58692
|
row,
|
|
58461
58693
|
destinations.platform,
|
|
58694
|
+
destinations.custom,
|
|
58462
58695
|
client2,
|
|
58463
58696
|
configuration,
|
|
58464
58697
|
options?.routingBudget
|
|
@@ -58580,6 +58813,7 @@ async function reconcilePublicProjectForOperation(env2, db, projectId, configura
|
|
|
58580
58813
|
project2,
|
|
58581
58814
|
row,
|
|
58582
58815
|
destinations.platform,
|
|
58816
|
+
destinations.custom,
|
|
58583
58817
|
client2,
|
|
58584
58818
|
configuration,
|
|
58585
58819
|
routingBudget
|
|
@@ -58659,7 +58893,7 @@ async function cleanupProjectZeroTrust(env2, db, projectId) {
|
|
|
58659
58893
|
await client2.deleteApplication(row.bypass_application_id, row.bypass_application_name);
|
|
58660
58894
|
await client2.deleteApplication(row.protected_application_id, row.protected_application_name);
|
|
58661
58895
|
}
|
|
58662
|
-
async function reconcileProjectZeroTrustDomains(env2, db, projectId) {
|
|
58896
|
+
async function reconcileProjectZeroTrustDomains(env2, db, projectId, options) {
|
|
58663
58897
|
const [configuration, row] = await Promise.all([
|
|
58664
58898
|
readZeroTrustConfigurationStrict(db),
|
|
58665
58899
|
getProjectZeroTrustState(db, projectId)
|
|
@@ -58667,7 +58901,10 @@ async function reconcileProjectZeroTrustDomains(env2, db, projectId) {
|
|
|
58667
58901
|
if (!configuration?.enabled || configuration.operation?.kind === "disable" || !row) {
|
|
58668
58902
|
return row;
|
|
58669
58903
|
}
|
|
58670
|
-
return reconcileProjectZeroTrust(env2, db, projectId, {
|
|
58904
|
+
return reconcileProjectZeroTrust(env2, db, projectId, {
|
|
58905
|
+
duringOperation: true,
|
|
58906
|
+
verifiedDomainId: options?.verifiedDomainId
|
|
58907
|
+
});
|
|
58671
58908
|
}
|
|
58672
58909
|
var init_project = __esm({
|
|
58673
58910
|
"../../home/runner/work/void/void/platform/packages/api/src/zero-trust/project.ts"() {
|
|
@@ -128664,6 +128901,7 @@ function ZeroTrustPage({ path, platformName, username }) {
|
|
|
128664
128901
|
operation?.existingProjects === "public" ? "public" : "protected"
|
|
128665
128902
|
);
|
|
128666
128903
|
const badge = statusBadge(configured, enabled, status2 ?? null);
|
|
128904
|
+
const publicOnly = configured && status2 !== "invalid_configuration" && identityProviderIds.length === 0 && policyIds.length === 0;
|
|
128667
128905
|
return /* @__PURE__ */ jsx5(Layout2, { platformName, title: "Zero Trust", username, children: /* @__PURE__ */ jsxs2("div", { className: "void-admin-zero-trust", children: [
|
|
128668
128906
|
/* @__PURE__ */ jsxs2("header", { className: "void-admin-zero-trust-intro", children: [
|
|
128669
128907
|
/* @__PURE__ */ jsx5(Heading, { level: 1, children: "Project Zero Trust" }),
|
|
@@ -128734,6 +128972,7 @@ function ZeroTrustPage({ path, platformName, username }) {
|
|
|
128734
128972
|
operation && /* @__PURE__ */ jsx5("p", { children: "To replace an expired or revoked token, keep the saved settings and submit a new token. The pending operation will resume." })
|
|
128735
128973
|
] }),
|
|
128736
128974
|
/* @__PURE__ */ jsxs2("form", { method: "post", action: `${HOME4}/configure`, className: "void-admin-zero-trust-form", children: [
|
|
128975
|
+
publicOnly && /* @__PURE__ */ jsx5("p", { children: "Void manages public app rules for this account. Leave policy fields blank to replace its token, or enter company identities and policies to configure protection." }),
|
|
128737
128976
|
/* @__PURE__ */ jsx5(
|
|
128738
128977
|
FormTextInput,
|
|
128739
128978
|
{
|
|
@@ -128751,8 +128990,8 @@ function ZeroTrustPage({ path, platformName, username }) {
|
|
|
128751
128990
|
label: "Identity provider IDs",
|
|
128752
128991
|
name: "identityProviderIds",
|
|
128753
128992
|
initialValue: identityProviderIds.join(", "),
|
|
128754
|
-
description: "Separate IDs with commas or spaces.",
|
|
128755
|
-
required:
|
|
128993
|
+
description: publicOnly ? "Leave blank to keep public app rules, or enter company IDs to configure protection." : "Separate IDs with commas or spaces.",
|
|
128994
|
+
required: !publicOnly,
|
|
128756
128995
|
width: 480
|
|
128757
128996
|
}
|
|
128758
128997
|
),
|
|
@@ -128763,7 +129002,7 @@ function ZeroTrustPage({ path, platformName, username }) {
|
|
|
128763
129002
|
name: "policyIds",
|
|
128764
129003
|
initialValue: policyIds.join(", "),
|
|
128765
129004
|
description: "Separate IDs with commas or spaces.",
|
|
128766
|
-
required:
|
|
129005
|
+
required: !publicOnly,
|
|
128767
129006
|
width: 480
|
|
128768
129007
|
}
|
|
128769
129008
|
),
|
|
@@ -128803,7 +129042,7 @@ function ZeroTrustPage({ path, platformName, username }) {
|
|
|
128803
129042
|
{
|
|
128804
129043
|
method: "post",
|
|
128805
129044
|
action: `${HOME4}/disable`,
|
|
128806
|
-
"data-confirm": "
|
|
129045
|
+
"data-confirm": "Remove Void-managed Access protection? Apps may become public or be blocked by account-wide Default-Deny.",
|
|
128807
129046
|
children: /* @__PURE__ */ jsx5(
|
|
128808
129047
|
Button,
|
|
128809
129048
|
{
|
|
@@ -129616,21 +129855,28 @@ async function zeroTrustStatus(env2, db, options = {}) {
|
|
|
129616
129855
|
try {
|
|
129617
129856
|
env2 = await resolveZeroTrustApplicationEnvironment(env2, db, configuration);
|
|
129618
129857
|
const client2 = await clientForConfiguration(env2, configuration);
|
|
129619
|
-
const selection = await client2.validateSelection({
|
|
129858
|
+
const selection = configuration.publicAccess ? await client2.getOrganization() : await client2.validateSelection({
|
|
129620
129859
|
identityProviderIds: configuration.identityProviderIds,
|
|
129621
129860
|
policyIds: configuration.policyIds
|
|
129622
129861
|
});
|
|
129623
|
-
live = await client2.inspectApplication(
|
|
129624
|
-
|
|
129625
|
-
|
|
129626
|
-
|
|
129627
|
-
|
|
129628
|
-
|
|
129862
|
+
live = await client2.inspectApplication(
|
|
129863
|
+
configuration.wildcardApplication,
|
|
129864
|
+
configuration.publicAccess ? publicAppManagementApplication(
|
|
129865
|
+
configuration.wildcardApplicationName,
|
|
129866
|
+
configuration.publicAccessGuardDestination
|
|
129867
|
+
) : {
|
|
129868
|
+
name: configuration.wildcardApplicationName,
|
|
129869
|
+
destinations: zeroTrustWildcardDestinations(readPlatformApplication(env2)),
|
|
129870
|
+
allowedIdentityProviderIds: configuration.identityProviderIds,
|
|
129871
|
+
policies: reusablePolicyReferences(configuration.policyIds)
|
|
129872
|
+
}
|
|
129873
|
+
);
|
|
129629
129874
|
const healthHostname = platformHealthHostname(readPlatformApplication(env2));
|
|
129630
129875
|
if (healthHostname) {
|
|
129631
|
-
const health = configuration.healthApplication ? await client2.
|
|
129876
|
+
const health = configuration.healthApplication ? await client2.inspectHealthApplication(
|
|
129632
129877
|
configuration.healthApplication,
|
|
129633
|
-
|
|
129878
|
+
configuration.healthApplicationName,
|
|
129879
|
+
healthHostname
|
|
129634
129880
|
) : { present: false, drifted: true };
|
|
129635
129881
|
live = {
|
|
129636
129882
|
present: live.present && health.present,
|
|
@@ -149935,10 +150181,17 @@ async function handleManifestOnlyDeploy(context) {
|
|
|
149935
150181
|
terminalEvent = event;
|
|
149936
150182
|
return;
|
|
149937
150183
|
}
|
|
149938
|
-
persistedEvents = persistedEvents.then(
|
|
149939
|
-
(
|
|
149940
|
-
|
|
149941
|
-
|
|
150184
|
+
persistedEvents = persistedEvents.then(async () => {
|
|
150185
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
150186
|
+
try {
|
|
150187
|
+
await appendDeploymentEvent(context.get("db"), preDeployment.id, cutoverOwnerId, event);
|
|
150188
|
+
return;
|
|
150189
|
+
} catch (error63) {
|
|
150190
|
+
if (attempt === 1) {
|
|
150191
|
+
logger.warn("progress", "persist_failed", { event: event.event, err: String(error63) });
|
|
150192
|
+
}
|
|
150193
|
+
}
|
|
150194
|
+
}
|
|
149942
150195
|
});
|
|
149943
150196
|
return;
|
|
149944
150197
|
}
|
|
@@ -152796,7 +153049,14 @@ async function deploymentExecutionStatus(db, installationId2) {
|
|
|
152796
153049
|
});
|
|
152797
153050
|
}
|
|
152798
153051
|
async function getDeploymentOperation(db, id2) {
|
|
152799
|
-
const [operation] = await db.select(
|
|
153052
|
+
const [operation] = await db.select({
|
|
153053
|
+
...getTableColumns(deploymentOperations),
|
|
153054
|
+
// The stored lease is a timestamp without time zone. Resolve it in the
|
|
153055
|
+
// SQL session's zone so observers receive an unambiguous UTC instant.
|
|
153056
|
+
lease_expires_at: sql`to_char(
|
|
153057
|
+
${deploymentOperations.lease_expires_at} AT TIME ZONE current_setting('TimeZone') AT TIME ZONE 'UTC',
|
|
153058
|
+
'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')`
|
|
153059
|
+
}).from(deploymentOperations).where(eq(deploymentOperations.id, id2));
|
|
152800
153060
|
return operation ?? null;
|
|
152801
153061
|
}
|
|
152802
153062
|
async function findDeploymentOperation(db, projectId, actorId, key) {
|
|
@@ -152886,7 +153146,18 @@ function deploymentEventPage(operation, since) {
|
|
|
152886
153146
|
deploymentId: operation.id,
|
|
152887
153147
|
events,
|
|
152888
153148
|
lastSeq,
|
|
152889
|
-
terminal: operation.status === "terminal" && lastSeq >= operation.last_seq
|
|
153149
|
+
terminal: operation.status === "terminal" && lastSeq >= operation.last_seq,
|
|
153150
|
+
...operation.status !== "terminal" && {
|
|
153151
|
+
heartbeat: {
|
|
153152
|
+
event: "heartbeat",
|
|
153153
|
+
deploymentId: operation.id,
|
|
153154
|
+
step: operation.status === "recovering" ? "recovery" : operation.events.at(-1)?.event.event ?? "queued",
|
|
153155
|
+
status: operation.status,
|
|
153156
|
+
...operation.lease_expires_at && {
|
|
153157
|
+
recoveryAt: new Date(operation.lease_expires_at).toISOString()
|
|
153158
|
+
}
|
|
153159
|
+
}
|
|
153160
|
+
}
|
|
152890
153161
|
};
|
|
152891
153162
|
}
|
|
152892
153163
|
function deploymentReceiptResponse(db, id2) {
|
|
@@ -152922,7 +153193,8 @@ function deploymentReceiptResponse(db, id2) {
|
|
|
152922
153193
|
return;
|
|
152923
153194
|
}
|
|
152924
153195
|
if (!page.events.length) {
|
|
152925
|
-
controller.enqueue(encoder12.encode(
|
|
153196
|
+
controller.enqueue(encoder12.encode(`${JSON.stringify(page.heartbeat)}
|
|
153197
|
+
`));
|
|
152926
153198
|
}
|
|
152927
153199
|
timer = setTimeout(() => {
|
|
152928
153200
|
void poll();
|
|
@@ -154842,10 +155114,10 @@ async function runConfigureOperation(env2, db, initial, suppliedClient, supplied
|
|
|
154842
155114
|
try {
|
|
154843
155115
|
env2 = await resolveZeroTrustApplicationEnvironment(env2, db, configuration);
|
|
154844
155116
|
const client2 = suppliedClient ?? await clientForConfiguration(env2, configuration);
|
|
154845
|
-
const selection = suppliedSelection ?? await client2.validateSelection({
|
|
155117
|
+
const selection = suppliedSelection ?? await (configuration.publicAccess ? client2.getOrganization() : client2.validateSelection({
|
|
154846
155118
|
identityProviderIds: configuration.identityProviderIds,
|
|
154847
155119
|
policyIds: configuration.policyIds
|
|
154848
|
-
});
|
|
155120
|
+
}));
|
|
154849
155121
|
if (selection.teamDomain !== configuration.teamDomain) {
|
|
154850
155122
|
configuration = await patchConfiguration(db, configuration, {
|
|
154851
155123
|
teamDomain: selection.teamDomain
|
|
@@ -154944,15 +155216,13 @@ async function runConfigureOperation(env2, db, initial, suppliedClient, supplied
|
|
|
154944
155216
|
}
|
|
154945
155217
|
const name = configuration.wildcardApplicationName;
|
|
154946
155218
|
configuration = await withZeroTrustOperationLock(db, configuration, async (lockedDb) => {
|
|
154947
|
-
const health = healthHostname && configuration.healthApplicationName ? await client2.
|
|
154948
|
-
|
|
154949
|
-
|
|
154950
|
-
|
|
154951
|
-
name: configuration.healthApplicationName
|
|
154952
|
-
}
|
|
155219
|
+
const health = healthHostname && configuration.healthApplicationName ? await client2.ensureHealthApplication(
|
|
155220
|
+
configuration.healthApplicationName,
|
|
155221
|
+
healthHostname,
|
|
155222
|
+
configuration.healthApplication
|
|
154953
155223
|
) : configuration.healthApplication;
|
|
154954
155224
|
const wildcard = await client2.ensureApplication(
|
|
154955
|
-
{
|
|
155225
|
+
configuration.publicAccess ? publicAppManagementApplication(name, configuration.publicAccessGuardDestination) : {
|
|
154956
155226
|
name,
|
|
154957
155227
|
destinations: zeroTrustWildcardDestinations(readPlatformApplication(env2)),
|
|
154958
155228
|
allowedIdentityProviderIds: configuration.identityProviderIds,
|
|
@@ -155140,10 +155410,12 @@ async function runDisableOperation(env2, db, initial) {
|
|
|
155140
155410
|
configuration.wildcardApplication?.id,
|
|
155141
155411
|
configuration.wildcardApplicationName
|
|
155142
155412
|
);
|
|
155143
|
-
|
|
155144
|
-
|
|
155145
|
-
|
|
155146
|
-
|
|
155413
|
+
if (!configuration.healthApplication || configuration.healthApplication.name === configuration.healthApplicationName) {
|
|
155414
|
+
await client2.deleteApplication(
|
|
155415
|
+
configuration.healthApplication?.id,
|
|
155416
|
+
configuration.healthApplicationName
|
|
155417
|
+
);
|
|
155418
|
+
}
|
|
155147
155419
|
return advanceOperation(lockedDb, configuration, "bypass-delete", {
|
|
155148
155420
|
enabled: false,
|
|
155149
155421
|
wildcardApplication: null,
|
|
@@ -155229,7 +155501,9 @@ async function activatePlatformApplication(env2, db, value) {
|
|
|
155229
155501
|
if (!current) {
|
|
155230
155502
|
throw new ZeroTrustUnavailableError("Project Zero Trust configuration is unavailable.");
|
|
155231
155503
|
}
|
|
155232
|
-
|
|
155504
|
+
if (!current.publicAccess) {
|
|
155505
|
+
assertWildcardExcludesControlPlane(env2, zeroTrustWildcardDestinations(target));
|
|
155506
|
+
}
|
|
155233
155507
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
155234
155508
|
const configuration = {
|
|
155235
155509
|
...current,
|
|
@@ -155284,6 +155558,16 @@ function assertWildcardExcludesControlPlane(env2, destinations, requestUrl) {
|
|
|
155284
155558
|
}
|
|
155285
155559
|
__name(assertWildcardExcludesControlPlane, "assertWildcardExcludesControlPlane");
|
|
155286
155560
|
function assertExistingProjectsChoice(current, input2) {
|
|
155561
|
+
if (input2.publicAccess && (input2.existingProjects === "protected" || input2.protectNewProjects || input2.identityProviderIds.length || input2.policyIds.length)) {
|
|
155562
|
+
throw new ZeroTrustUnavailableError(
|
|
155563
|
+
"Public app access cannot require identities or protect new projects."
|
|
155564
|
+
);
|
|
155565
|
+
}
|
|
155566
|
+
if (input2.publicAccess && current?.enabled && !current.publicAccess) {
|
|
155567
|
+
throw new ZeroTrustUnavailableError(
|
|
155568
|
+
"Disable the existing protected configuration before enabling public-only app rules."
|
|
155569
|
+
);
|
|
155570
|
+
}
|
|
155287
155571
|
const operation = current?.operation;
|
|
155288
155572
|
if (operation) {
|
|
155289
155573
|
if (input2.existingProjects === void 0 || input2.existingProjects === operation.existingProjects) {
|
|
@@ -155317,11 +155601,19 @@ async function configurePlatformZeroTrust(env2, db, input2, options = {}) {
|
|
|
155317
155601
|
const previous = await readZeroTrustConfigurationStrict(db);
|
|
155318
155602
|
assertExistingProjectsChoice(previous, input2);
|
|
155319
155603
|
const replacingDisableCredential = previous?.operation?.kind === "disable";
|
|
155320
|
-
if (!replacingDisableCredential) {
|
|
155604
|
+
if (!replacingDisableCredential && !input2.publicAccess) {
|
|
155321
155605
|
assertWildcardExcludesControlPlane(env2, destinations, options.requestUrl);
|
|
155322
155606
|
}
|
|
155607
|
+
const application = readPlatformApplication(env2);
|
|
155608
|
+
const publicGuardHostname = platformHealthHostname(application) ?? (application.workersDev && env2.DISPATCH_WORKER_NAME ? `${env2.DISPATCH_WORKER_NAME}.${application.workersDev.subdomain}.workers.dev` : null);
|
|
155609
|
+
if (input2.publicAccess && !publicGuardHostname) {
|
|
155610
|
+
throw new ZeroTrustUnavailableError(
|
|
155611
|
+
"The installation\u2019s reserved dispatch hostname is unavailable. Repair the installation before configuring public app rules."
|
|
155612
|
+
);
|
|
155613
|
+
}
|
|
155614
|
+
const publicAccessGuardDestination = input2.publicAccess ? publicAppManagementDestination("https://" + publicGuardHostname) : void 0;
|
|
155323
155615
|
const client2 = new ZeroTrustCloudflareClient(accountId, input2.apiToken);
|
|
155324
|
-
const selection = replacingDisableCredential ? await client2.getOrganization() : await client2.validateSelection(input2);
|
|
155616
|
+
const selection = replacingDisableCredential || input2.publicAccess ? await client2.getOrganization() : await client2.validateSelection(input2);
|
|
155325
155617
|
const credential = await encryptPlatformCredential(
|
|
155326
155618
|
env2,
|
|
155327
155619
|
installationId(env2),
|
|
@@ -155337,7 +155629,7 @@ async function configurePlatformZeroTrust(env2, db, input2, options = {}) {
|
|
|
155337
155629
|
assertExistingProjectsChoice(current, input2);
|
|
155338
155630
|
if (current?.operation) {
|
|
155339
155631
|
const sameIds = /* @__PURE__ */ __name((left, right) => left.length === right.length && left.every((id2) => right.includes(id2)), "sameIds");
|
|
155340
|
-
if (current.accountId !== accountId || current.protectNewProjects !== input2.protectNewProjects || !sameIds(current.identityProviderIds, input2.identityProviderIds) || !sameIds(current.policyIds, input2.policyIds)) {
|
|
155632
|
+
if (current.accountId !== accountId || !!current.publicAccess !== !!input2.publicAccess || current.protectNewProjects !== input2.protectNewProjects || !sameIds(current.identityProviderIds, input2.identityProviderIds) || !sameIds(current.policyIds, input2.policyIds)) {
|
|
155341
155633
|
throw new ZeroTrustUnavailableError(
|
|
155342
155634
|
"A saved Zero Trust operation is pending. To replace its API token, configure again with the same identity providers, policies, and project selections."
|
|
155343
155635
|
);
|
|
@@ -155355,6 +155647,8 @@ async function configurePlatformZeroTrust(env2, db, input2, options = {}) {
|
|
|
155355
155647
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
155356
155648
|
return {
|
|
155357
155649
|
version: 1,
|
|
155650
|
+
...input2.publicAccess ? { publicAccess: true, publicAccessGuardDestination } : {},
|
|
155651
|
+
...input2.managePublicCustomDomains || current?.managePublicCustomDomains ? { managePublicCustomDomains: true } : {},
|
|
155358
155652
|
revision: (current?.revision ?? 0) + 1,
|
|
155359
155653
|
enabled: current?.enabled ?? false,
|
|
155360
155654
|
protectNewProjects: input2.protectNewProjects,
|
|
@@ -155541,6 +155835,7 @@ zeroTrustOperatorRoutes.post("/zero-trust/configure", async (context) => {
|
|
|
155541
155835
|
return context.json(
|
|
155542
155836
|
preview("zero-trust.configure", "platform", {
|
|
155543
155837
|
accountId: context.env.CF_ACCOUNT_ID,
|
|
155838
|
+
...input2.publicAccess ? { appAccess: "public" } : {},
|
|
155544
155839
|
identityProviderIds: input2.identityProviderIds,
|
|
155545
155840
|
policyIds: input2.policyIds,
|
|
155546
155841
|
protectNewProjects: input2.protectNewProjects,
|
|
@@ -156616,7 +156911,9 @@ app11.post("/configure", async (context) => {
|
|
|
156616
156911
|
const form = await context.req.parseBody();
|
|
156617
156912
|
let input2;
|
|
156618
156913
|
try {
|
|
156914
|
+
const saved = await readZeroTrustConfigurationStrict(context.get("db"));
|
|
156619
156915
|
input2 = normalizeZeroTrustConfigureInput({
|
|
156916
|
+
publicAccess: !!saved?.publicAccess && !values(form.identityProviderIds).length && !values(form.policyIds).length,
|
|
156620
156917
|
apiToken: form.apiToken,
|
|
156621
156918
|
identityProviderIds: values(form.identityProviderIds),
|
|
156622
156919
|
policyIds: values(form.policyIds),
|
|
@@ -158108,7 +158405,7 @@ var import_headless = __toESM(require_xterm_headless(), 1);
|
|
|
158108
158405
|
// ../../home/runner/work/void/void/packages/void/package.json
|
|
158109
158406
|
var package_default = {
|
|
158110
158407
|
name: "void",
|
|
158111
|
-
version: "0.
|
|
158408
|
+
version: "0.24.0",
|
|
158112
158409
|
repository: {
|
|
158113
158410
|
type: "git",
|
|
158114
158411
|
url: "git+https://github.com/voidzero-dev/void.git",
|
|
@@ -158483,13 +158780,12 @@ var package_default = {
|
|
|
158483
158780
|
undici: "8.11.2"
|
|
158484
158781
|
},
|
|
158485
158782
|
devDependencies: {
|
|
158486
|
-
"@clack/core": "^1.5.1",
|
|
158487
|
-
"@clack/prompts": "catalog:",
|
|
158488
158783
|
"@electric-sql/pglite": "0.5.8",
|
|
158489
158784
|
"@types/better-sqlite3": "^9.6.0",
|
|
158490
158785
|
"@types/node": "catalog:",
|
|
158491
158786
|
"@types/pg": "^8.23.1",
|
|
158492
158787
|
"@types/proper-lockfile": "^4.1.4",
|
|
158788
|
+
"@voidzero-dev/vite-plus-prompts": "workspace:*",
|
|
158493
158789
|
arktype: "^2.2.5",
|
|
158494
158790
|
"ci-info": "^4.4.0",
|
|
158495
158791
|
"estree-walker": "^3.0.3",
|
|
@@ -160127,6 +160423,7 @@ var BuildManager = class extends Container {
|
|
|
160127
160423
|
SOURCE_TOKEN: sourceToken,
|
|
160128
160424
|
VOID_TOKEN: voidToken,
|
|
160129
160425
|
VOID_API_URL: voidApiUrl,
|
|
160426
|
+
...this.env.PROXY_URL ? { VOID_PROXY_URL: this.env.PROXY_URL } : {},
|
|
160130
160427
|
VOID_PROJECT: config2.projectSlug,
|
|
160131
160428
|
VOID_CLI_VERSION: PINNED_VOID_CLI_VERSION,
|
|
160132
160429
|
DO_LOG_URL: "https://manager/logs",
|
|
@@ -162308,7 +162605,8 @@ var platformAccessProtection = /* @__PURE__ */ __name(async (context, next) => {
|
|
|
162308
162605
|
const path = context.req.path;
|
|
162309
162606
|
const method = context.req.method;
|
|
162310
162607
|
const probe = context.env.PLATFORM_HEALTH_PROBE_TOKEN && context.req.header("X-Void-Platform-Probe") === context.env.PLATFORM_HEALTH_PROBE_TOKEN;
|
|
162311
|
-
if (path === "/.well-known/void-platform" && method === "GET" || probe && (path === "/health" && method === "GET" || path === "/internal/platform/sandbox-drain" && method === "GET" || path === "/__void/platform/deployment-execution" && method === "GET" || path === "/internal/platform/email-bootstrap" && method === "POST" ||
|
|
162608
|
+
if (path === "/.well-known/void-platform" && method === "GET" || probe && (path === "/health" && method === "GET" || path === "/internal/platform/sandbox-drain" && method === "GET" || path === "/__void/platform/deployment-execution" && method === "GET" || path === "/internal/platform/email-bootstrap" && method === "POST" || // The handler also requires its installation-specific setup HMAC.
|
|
162609
|
+
path === "/internal/platform/app-access" && method === "POST" || path === "/internal/platform/domain-preflight" && method === "POST" || path === "/internal/platform/domain-activate" && method === "POST")) {
|
|
162312
162610
|
return next();
|
|
162313
162611
|
}
|
|
162314
162612
|
if (path === "/auth/github-oidc" && method === "POST") {
|
|
@@ -164356,6 +164654,185 @@ operatorApi.notFound(
|
|
|
164356
164654
|
(context) => context.json({ error: "not_found", message: "Unknown operator API endpoint." }, 404)
|
|
164357
164655
|
);
|
|
164358
164656
|
|
|
164657
|
+
// ../../home/runner/work/void/void/platform/packages/api/src/platform-app-access.ts
|
|
164658
|
+
init_performance2();
|
|
164659
|
+
init_dist();
|
|
164660
|
+
init_drizzle_orm();
|
|
164661
|
+
init_platform_settings();
|
|
164662
|
+
init_cloudflare();
|
|
164663
|
+
init_configuration2();
|
|
164664
|
+
init_errors4();
|
|
164665
|
+
init_lock();
|
|
164666
|
+
init_status();
|
|
164667
|
+
var SETTING = "appAccess.installation.v1";
|
|
164668
|
+
function sameSelection(current, setup) {
|
|
164669
|
+
return current.accountId === setup.accountId && !!current.publicAccess === (setup.mode === "public") && current.protectNewProjects === (setup.mode === "protected") && JSON.stringify(current.identityProviderIds) === JSON.stringify(setup.identityProviderIds) && JSON.stringify(current.policyIds) === JSON.stringify(setup.policyIds);
|
|
164670
|
+
}
|
|
164671
|
+
__name(sameSelection, "sameSelection");
|
|
164672
|
+
async function initializePlatformAppAccess(env2, db, setup) {
|
|
164673
|
+
if (!env2.PLATFORM_APP_ACCESS || !env2.PLATFORM_INSTALLATION_ID || setup.accountId !== env2.CF_ACCOUNT_ID || setup.mode !== (env2.PLATFORM_APP_ACCESS === "public" ? "public" : "protected")) {
|
|
164674
|
+
throw new Error("App access does not match the installation\u2019s account or saved choice.");
|
|
164675
|
+
}
|
|
164676
|
+
const { apiToken: _token, ...identity } = setup;
|
|
164677
|
+
const digest2 = new Uint8Array(
|
|
164678
|
+
await crypto.subtle.digest("SHA-256", new TextEncoder().encode(JSON.stringify(identity)))
|
|
164679
|
+
);
|
|
164680
|
+
const requestHash = Array.from(digest2, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
164681
|
+
const claim2 = await db.transaction(async (tx) => {
|
|
164682
|
+
await lockZeroTrustConfiguration(tx, "exclusive");
|
|
164683
|
+
const value = await getPlatformSetting(tx, SETTING);
|
|
164684
|
+
const receipt = value;
|
|
164685
|
+
if (receipt && (receipt.version !== 1 || typeof receipt.requestHash !== "string" || typeof receipt.complete !== "boolean")) {
|
|
164686
|
+
throw new Error("The saved app access setup receipt is invalid.");
|
|
164687
|
+
}
|
|
164688
|
+
if (receipt?.complete) {
|
|
164689
|
+
return { complete: true };
|
|
164690
|
+
}
|
|
164691
|
+
if (receipt && receipt.requestHash !== requestHash) {
|
|
164692
|
+
throw new Error("Resume with the saved app access selections.");
|
|
164693
|
+
}
|
|
164694
|
+
const result = await tx.execute(
|
|
164695
|
+
sql`SELECT installation_id, lifecycle_manifest FROM __void_platform_installation WHERE singleton = true FOR SHARE`
|
|
164696
|
+
);
|
|
164697
|
+
const row = result.rows[0];
|
|
164698
|
+
if (!row || row.installation_id !== env2.PLATFORM_INSTALLATION_ID || row.lifecycle_manifest?.id !== env2.PLATFORM_INSTALLATION_ID || row.lifecycle_manifest?.deployment?.appAccess !== env2.PLATFORM_APP_ACCESS || !["provisioning", "deploying", "verifying"].includes(row.lifecycle_manifest?.status ?? "")) {
|
|
164699
|
+
throw new Error(
|
|
164700
|
+
"App access initialization is only available during the recorded installation setup."
|
|
164701
|
+
);
|
|
164702
|
+
}
|
|
164703
|
+
const current2 = await readZeroTrustConfigurationStrict(tx);
|
|
164704
|
+
if (!receipt && current2) {
|
|
164705
|
+
if (current2.operation || current2.lastError) {
|
|
164706
|
+
throw new Error("Reconcile the existing app access settings before resuming installation.");
|
|
164707
|
+
}
|
|
164708
|
+
await setPlatformSetting(tx, SETTING, {
|
|
164709
|
+
version: 1,
|
|
164710
|
+
requestHash,
|
|
164711
|
+
complete: true
|
|
164712
|
+
});
|
|
164713
|
+
return { complete: true };
|
|
164714
|
+
}
|
|
164715
|
+
if (current2 && !sameSelection(current2, setup)) {
|
|
164716
|
+
throw new Error(
|
|
164717
|
+
"App access was changed outside installation. Inspect Admin \u2192 Zero Trust before resuming."
|
|
164718
|
+
);
|
|
164719
|
+
}
|
|
164720
|
+
await setPlatformSetting(tx, SETTING, {
|
|
164721
|
+
version: 1,
|
|
164722
|
+
requestHash,
|
|
164723
|
+
complete: !setup.managed
|
|
164724
|
+
});
|
|
164725
|
+
return { complete: !setup.managed };
|
|
164726
|
+
});
|
|
164727
|
+
if (claim2.complete) {
|
|
164728
|
+
return { ready: true };
|
|
164729
|
+
}
|
|
164730
|
+
const current = await readZeroTrustConfigurationStrict(db);
|
|
164731
|
+
if (current?.operation?.kind === "disable") {
|
|
164732
|
+
throw new Error(
|
|
164733
|
+
"An administrator is disabling app access. Finish that operation before resuming installation."
|
|
164734
|
+
);
|
|
164735
|
+
}
|
|
164736
|
+
const existingProjects = current?.operation ? current.operation.existingProjects ?? void 0 : current?.enabled ? void 0 : setup.mode === "protected" ? "protected" : "public";
|
|
164737
|
+
await configurePlatformZeroTrust(env2, db, {
|
|
164738
|
+
apiToken: setup.apiToken,
|
|
164739
|
+
identityProviderIds: setup.identityProviderIds,
|
|
164740
|
+
policyIds: setup.policyIds,
|
|
164741
|
+
protectNewProjects: setup.mode === "protected",
|
|
164742
|
+
...existingProjects ? { existingProjects } : {},
|
|
164743
|
+
...setup.mode === "public" ? { publicAccess: true } : {},
|
|
164744
|
+
managePublicCustomDomains: true
|
|
164745
|
+
});
|
|
164746
|
+
const status2 = await zeroTrustStatus(env2, db, { check: true });
|
|
164747
|
+
if (!status2.enabled || status2.status !== "ready" || !status2.live?.present || status2.live.drifted || status2.projects.some((project2) => project2.state === "error" || project2.state === "reconciling")) {
|
|
164748
|
+
return { ready: false };
|
|
164749
|
+
}
|
|
164750
|
+
await db.transaction(async (tx) => {
|
|
164751
|
+
await lockZeroTrustConfiguration(tx, "exclusive");
|
|
164752
|
+
const receipt = await getPlatformSetting(tx, SETTING);
|
|
164753
|
+
const current2 = await readZeroTrustConfigurationStrict(tx);
|
|
164754
|
+
if (receipt?.requestHash !== requestHash || !current2 || !sameSelection(current2, setup) || current2.operation || current2.lastError) {
|
|
164755
|
+
throw new Error("App access changed while setup was being verified. Resume installation.");
|
|
164756
|
+
}
|
|
164757
|
+
await setPlatformSetting(tx, SETTING, { ...receipt, complete: true });
|
|
164758
|
+
});
|
|
164759
|
+
return { ready: true };
|
|
164760
|
+
}
|
|
164761
|
+
__name(initializePlatformAppAccess, "initializePlatformAppAccess");
|
|
164762
|
+
async function platformAppAccess(context) {
|
|
164763
|
+
const token = context.env.PLATFORM_HEALTH_PROBE_TOKEN;
|
|
164764
|
+
if (!token || context.req.header("X-Void-Platform-Probe") !== token || !context.env.PLATFORM_INSTALLATION_ID || !context.env.PLATFORM_APP_ACCESS) {
|
|
164765
|
+
return context.json({ error: "not found" }, 404);
|
|
164766
|
+
}
|
|
164767
|
+
const setupKey = context.env.PLATFORM_APP_ACCESS_SETUP_TOKEN;
|
|
164768
|
+
const signature = context.req.header("X-Void-App-Access-Setup") ?? "";
|
|
164769
|
+
if (!setupKey || setupKey.length < 32 || !/^[A-Za-z0-9_-]{43}$/.test(signature)) {
|
|
164770
|
+
return context.json({ error: "not found" }, 404);
|
|
164771
|
+
}
|
|
164772
|
+
const body = await context.req.text();
|
|
164773
|
+
const key = await crypto.subtle.importKey(
|
|
164774
|
+
"raw",
|
|
164775
|
+
new TextEncoder().encode(setupKey),
|
|
164776
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
164777
|
+
false,
|
|
164778
|
+
["verify"]
|
|
164779
|
+
);
|
|
164780
|
+
const proof = Uint8Array.from(
|
|
164781
|
+
atob(signature.replaceAll("-", "+").replaceAll("_", "/")),
|
|
164782
|
+
(byte) => byte.charCodeAt(0)
|
|
164783
|
+
);
|
|
164784
|
+
if (!await crypto.subtle.verify(
|
|
164785
|
+
"HMAC",
|
|
164786
|
+
key,
|
|
164787
|
+
proof,
|
|
164788
|
+
new TextEncoder().encode(
|
|
164789
|
+
`${PLATFORM_APP_ACCESS_SETUP_PROOF_PREFIX}
|
|
164790
|
+
${context.env.PLATFORM_INSTALLATION_ID}
|
|
164791
|
+
${body}`
|
|
164792
|
+
)
|
|
164793
|
+
)) {
|
|
164794
|
+
return context.json({ error: "not found" }, 404);
|
|
164795
|
+
}
|
|
164796
|
+
let setup;
|
|
164797
|
+
try {
|
|
164798
|
+
setup = parsePlatformAppAccessSetup(JSON.parse(body));
|
|
164799
|
+
} catch {
|
|
164800
|
+
return context.json({ error: "Invalid app access setup." }, 400);
|
|
164801
|
+
}
|
|
164802
|
+
try {
|
|
164803
|
+
const receipt = await getPlatformSetting(context.get("db"), SETTING);
|
|
164804
|
+
if (!receipt?.complete && context.env.PLATFORM_TRAFFIC_STATE !== "staging" && await context.env.ROUTING.get(PLATFORM_DISABLED_KEY) !== PLATFORM_DISABLED_VALUE) {
|
|
164805
|
+
return context.json({ error: "Close app traffic before initializing app access." }, 409);
|
|
164806
|
+
}
|
|
164807
|
+
const result = await initializePlatformAppAccess(context.env, context.get("db"), setup);
|
|
164808
|
+
return context.json(
|
|
164809
|
+
{ installationId: context.env.PLATFORM_INSTALLATION_ID, ...result },
|
|
164810
|
+
result.ready ? 200 : 202
|
|
164811
|
+
);
|
|
164812
|
+
} catch (error63) {
|
|
164813
|
+
console.error("[platform] app access setup failed", error63);
|
|
164814
|
+
if (error63 instanceof ZeroTrustCloudflareError && [401, 403].includes(error63.status)) {
|
|
164815
|
+
return context.json(
|
|
164816
|
+
{
|
|
164817
|
+
error: "The app access token needs Access Apps and Policies Edit plus Organizations, Identity Providers, and Groups Read in the hosting account.",
|
|
164818
|
+
code: "app_access_credentials"
|
|
164819
|
+
},
|
|
164820
|
+
403
|
|
164821
|
+
);
|
|
164822
|
+
}
|
|
164823
|
+
if (error63 instanceof ZeroTrustUnavailableError) {
|
|
164824
|
+
return context.json({ error: error63.message }, 409);
|
|
164825
|
+
}
|
|
164826
|
+
return context.json(
|
|
164827
|
+
{
|
|
164828
|
+
error: "App access is not ready. Check the Access token, identity providers, and policy selections, then resume."
|
|
164829
|
+
},
|
|
164830
|
+
503
|
|
164831
|
+
);
|
|
164832
|
+
}
|
|
164833
|
+
}
|
|
164834
|
+
__name(platformAppAccess, "platformAppAccess");
|
|
164835
|
+
|
|
164359
164836
|
// ../../home/runner/work/void/void/platform/packages/api/src/platform-domain-activation.ts
|
|
164360
164837
|
init_performance2();
|
|
164361
164838
|
init_configuration2();
|
|
@@ -164869,7 +165346,7 @@ async function tryActivateDomain(env2, db, domain2, project2, options) {
|
|
|
164869
165346
|
let slugRouting = null;
|
|
164870
165347
|
let activated = false;
|
|
164871
165348
|
if (gateOk && wasPending) {
|
|
164872
|
-
await reconcileProjectZeroTrustDomains(env2, db, project2.id);
|
|
165349
|
+
await reconcileProjectZeroTrustDomains(env2, db, project2.id, { verifiedDomainId: domain2.id });
|
|
164873
165350
|
await db.transaction(async (tx) => {
|
|
164874
165351
|
await tx.execute(sql`SELECT id FROM projects WHERE id = ${project2.id} FOR UPDATE`);
|
|
164875
165352
|
const txDb = tx;
|
|
@@ -174689,7 +175166,7 @@ var app36 = new Hono3().use("*", async (context, next) => {
|
|
|
174689
175166
|
return context.json({ error: "Internal Server Error" }, 500);
|
|
174690
175167
|
}).use("*", async (context, next) => {
|
|
174691
175168
|
const healthProbeToken = context.env.PLATFORM_HEALTH_PROBE_TOKEN;
|
|
174692
|
-
const installerProbe = healthProbeToken !== void 0 && healthProbeToken !== "" && context.req.header("X-Void-Platform-Probe") === healthProbeToken && (context.req.path === "/health" || context.req.path === "/.well-known/void-platform" || context.req.path === "/internal/platform/sandbox-drain" || context.req.path === "/__void/platform/deployment-execution" || context.req.path === "/internal/platform/email-bootstrap" && context.req.method === "POST" || context.req.path === "/internal/platform/domain-preflight" && context.req.method === "POST" || context.req.path === "/internal/platform/domain-activate" && context.req.method === "POST");
|
|
175169
|
+
const installerProbe = healthProbeToken !== void 0 && healthProbeToken !== "" && context.req.header("X-Void-Platform-Probe") === healthProbeToken && (context.req.path === "/health" || context.req.path === "/.well-known/void-platform" || context.req.path === "/internal/platform/sandbox-drain" || context.req.path === "/__void/platform/deployment-execution" || context.req.path === "/internal/platform/email-bootstrap" && context.req.method === "POST" || context.req.path === "/internal/platform/app-access" && context.req.method === "POST" || context.req.path === "/internal/platform/domain-preflight" && context.req.method === "POST" || context.req.path === "/internal/platform/domain-activate" && context.req.method === "POST");
|
|
174693
175170
|
const maintenanceSandboxDrain = context.env.PLATFORM_TRAFFIC_STATE === "sandbox-drain" && isSandboxDrainMaintenanceRequest(context.req.raw);
|
|
174694
175171
|
const authenticationSetup = context.env.PLATFORM_AUTH_SETUP_TOKEN && context.req.header("X-Void-Auth-Setup") && context.req.method === "POST" && context.req.path === "/internal/platform/auth-initialize";
|
|
174695
175172
|
if (!authenticationSetup && !installerProbe && !maintenanceSandboxDrain && (context.env.PLATFORM_TRAFFIC_STATE === "staging" || context.env.PLATFORM_TRAFFIC_STATE === "sandbox-drain" || context.env.PLATFORM_INSTALLATION_ID && await context.env.ROUTING.get(PLATFORM_DISABLED_KEY) === PLATFORM_DISABLED_VALUE)) {
|
|
@@ -174764,7 +175241,7 @@ var app36 = new Hono3().use("*", async (context, next) => {
|
|
|
174764
175241
|
usageProtocolVersion: USAGE_PROTOCOL_VERSION
|
|
174765
175242
|
})
|
|
174766
175243
|
);
|
|
174767
|
-
}).post("/internal/platform/domain-preflight", platformDomainPreflight).post("/internal/platform/domain-activate", platformDomainActivation).post("/internal/platform/email-bootstrap", async (context) => {
|
|
175244
|
+
}).post("/internal/platform/app-access", platformAppAccess).post("/internal/platform/domain-preflight", platformDomainPreflight).post("/internal/platform/domain-activate", platformDomainActivation).post("/internal/platform/email-bootstrap", async (context) => {
|
|
174768
175245
|
const healthProbeToken = context.env.PLATFORM_HEALTH_PROBE_TOKEN;
|
|
174769
175246
|
if (!healthProbeToken || context.req.header("X-Void-Platform-Probe") !== healthProbeToken || !context.env.PLATFORM_INSTALLATION_ID || !getPlatformCapabilities(context.env).email) {
|
|
174770
175247
|
return context.json({ error: "not found" }, 404);
|