@wtfalch/foundry 0.75.0 → 0.76.1
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/dist/plan/desktop-auth.d.ts +17 -4
- package/dist/plan/desktop-auth.js +22 -5
- package/dist/plan/executor.js +7 -1
- package/dist/plan/own-diff.js +3 -1
- package/dist/plan/platform-diff.d.ts +10 -0
- package/dist/plan/platform-diff.js +12 -0
- package/dist/plan/platform-providers.d.ts +16 -0
- package/dist/plan/platform-providers.js +68 -6
- package/package.json +1 -1
- package/versions.digests.json +1 -1
- package/versions.json +1 -1
|
@@ -13,6 +13,17 @@ export declare const DESKTOP_AUTH_HOME = "desktop_auth";
|
|
|
13
13
|
export declare const DESKTOP_AUTH_REVISION_SCOPE_KEY = "coolify_desktop_auth_revision";
|
|
14
14
|
/** The Agora origin the app was last written for (CLAUDE.md rule 3: the applied hostname is a scope id). */
|
|
15
15
|
export declare const DESKTOP_AUTH_ORIGIN_SCOPE_KEY = "coolify_desktop_auth_origin";
|
|
16
|
+
/**
|
|
17
|
+
* The org's one shared Postgres server ({@link ORG_POSTGRES_SERVER_SCOPE_KEY}) that desktop-auth's
|
|
18
|
+
* `MESSAGING_DATABASE_URL`/`MESSAGING_DATABASE_URL_OWNER` were last written for. Those two env values
|
|
19
|
+
* are built from the server's live `internal_db_url` at apply time (`executor.ts`'s `serverHome`), so a
|
|
20
|
+
* server that is re-provisioned under a new Coolify resource is always picked up correctly *once this
|
|
21
|
+
* step actually runs* -- but {@link DESKTOP_AUTH_REVISION_SCOPE_KEY} hashes only `desktopAuthEnv`'s
|
|
22
|
+
* fields, which never include the database host. Without this scope key a server change that leaves
|
|
23
|
+
* every other input (issuer, client id, org id, project ids) unchanged never replans the step at all, and
|
|
24
|
+
* the app keeps restarting against a host that no longer exists (foundry#1112).
|
|
25
|
+
*/
|
|
26
|
+
export declare const DESKTOP_AUTH_DB_SERVER_SCOPE_KEY = "coolify_desktop_auth_db_server";
|
|
16
27
|
/** The callback URI last put on Agora's client, or `unsupported:<uri>` when the providers client cannot. */
|
|
17
28
|
export declare const DESKTOP_AUTH_REDIRECT_SCOPE_KEY = "coolify_desktop_auth_redirect";
|
|
18
29
|
/** Recorded once the readiness probe through Agora answered. */
|
|
@@ -43,10 +54,12 @@ export declare function desktopAuthEnv(inputs: DesktopAuthInputs, runtimeRole: s
|
|
|
43
54
|
export declare function desktopAuthRevision(env: Readonly<Record<string, string>>): string;
|
|
44
55
|
/**
|
|
45
56
|
* The `coolify:desktop-auth` step. Planned when the app is not recorded, when the env it was written for
|
|
46
|
-
* differs (a rename moves the origin), when
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
57
|
+
* differs (a rename moves the origin), when the org's Postgres server has changed since the env was last
|
|
58
|
+
* written (foundry#1112: the database host is not part of that revision, since it is built from a live
|
|
59
|
+
* Coolify read the plan itself cannot make), when it never ran healthy, when the callback URI is not on
|
|
60
|
+
* Agora's client, and when Agora carries the upstream but the readiness probe never answered. Not planned
|
|
61
|
+
* while Agora is blocked (its own line says why) or while the `desktop_auth` home cannot exist yet
|
|
62
|
+
* (blocked). `homePlanned` is true when the databases step in this plan creates the home.
|
|
50
63
|
*/
|
|
51
64
|
export declare function planDesktopAuth(org: DeclaredOrg, recorded: Readonly<Record<string, string>>, input: {
|
|
52
65
|
host: AgoraHostValues | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import { ORG_SERVICE_SCHEMAS, orgServiceDatabase } from '../org.js';
|
|
2
|
+
import { ORG_POSTGRES_SERVER_SCOPE_KEY, ORG_SERVICE_SCHEMAS, orgServiceDatabase, } from '../org.js';
|
|
3
3
|
import { AGORA_CLIENT_ID_SCOPE_KEY, DESKTOP_AUTH_APP_SCOPE_KEY, DESKTOP_AUTH_DEPLOYED_SCOPE_KEY, DESKTOP_AUTH_PORT, ZITADEL_ORG_SCOPE_KEY, agoraHostnameFor, desktopAuthInternalName, desktopAuthUpstream, withRecordedMessagingProject, } from './agora.js';
|
|
4
4
|
import { ZITADEL_FILES_PROJECT_SCOPE_KEY } from './core-files.js';
|
|
5
5
|
export { DESKTOP_AUTH_APP_SCOPE_KEY, DESKTOP_AUTH_DEPLOYED_SCOPE_KEY, DESKTOP_AUTH_PORT, desktopAuthInternalName, desktopAuthUpstream, };
|
|
@@ -14,6 +14,17 @@ export const DESKTOP_AUTH_HOME = 'desktop_auth';
|
|
|
14
14
|
export const DESKTOP_AUTH_REVISION_SCOPE_KEY = 'coolify_desktop_auth_revision';
|
|
15
15
|
/** The Agora origin the app was last written for (CLAUDE.md rule 3: the applied hostname is a scope id). */
|
|
16
16
|
export const DESKTOP_AUTH_ORIGIN_SCOPE_KEY = 'coolify_desktop_auth_origin';
|
|
17
|
+
/**
|
|
18
|
+
* The org's one shared Postgres server ({@link ORG_POSTGRES_SERVER_SCOPE_KEY}) that desktop-auth's
|
|
19
|
+
* `MESSAGING_DATABASE_URL`/`MESSAGING_DATABASE_URL_OWNER` were last written for. Those two env values
|
|
20
|
+
* are built from the server's live `internal_db_url` at apply time (`executor.ts`'s `serverHome`), so a
|
|
21
|
+
* server that is re-provisioned under a new Coolify resource is always picked up correctly *once this
|
|
22
|
+
* step actually runs* -- but {@link DESKTOP_AUTH_REVISION_SCOPE_KEY} hashes only `desktopAuthEnv`'s
|
|
23
|
+
* fields, which never include the database host. Without this scope key a server change that leaves
|
|
24
|
+
* every other input (issuer, client id, org id, project ids) unchanged never replans the step at all, and
|
|
25
|
+
* the app keeps restarting against a host that no longer exists (foundry#1112).
|
|
26
|
+
*/
|
|
27
|
+
export const DESKTOP_AUTH_DB_SERVER_SCOPE_KEY = 'coolify_desktop_auth_db_server';
|
|
17
28
|
/** The callback URI last put on Agora's client, or `unsupported:<uri>` when the providers client cannot. */
|
|
18
29
|
export const DESKTOP_AUTH_REDIRECT_SCOPE_KEY = 'coolify_desktop_auth_redirect';
|
|
19
30
|
/** Recorded once the readiness probe through Agora answered. */
|
|
@@ -85,10 +96,12 @@ function runtimeRoleFor(org) {
|
|
|
85
96
|
}
|
|
86
97
|
/**
|
|
87
98
|
* The `coolify:desktop-auth` step. Planned when the app is not recorded, when the env it was written for
|
|
88
|
-
* differs (a rename moves the origin), when
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
99
|
+
* differs (a rename moves the origin), when the org's Postgres server has changed since the env was last
|
|
100
|
+
* written (foundry#1112: the database host is not part of that revision, since it is built from a live
|
|
101
|
+
* Coolify read the plan itself cannot make), when it never ran healthy, when the callback URI is not on
|
|
102
|
+
* Agora's client, and when Agora carries the upstream but the readiness probe never answered. Not planned
|
|
103
|
+
* while Agora is blocked (its own line says why) or while the `desktop_auth` home cannot exist yet
|
|
104
|
+
* (blocked). `homePlanned` is true when the databases step in this plan creates the home.
|
|
92
105
|
*/
|
|
93
106
|
export function planDesktopAuth(org, recorded, input) {
|
|
94
107
|
if (!input.host)
|
|
@@ -114,6 +127,10 @@ export function planDesktopAuth(org, recorded, input) {
|
|
|
114
127
|
else {
|
|
115
128
|
if (revision && recorded[DESKTOP_AUTH_REVISION_SCOPE_KEY] !== revision)
|
|
116
129
|
reasons.push('env');
|
|
130
|
+
const dbServer = recorded[ORG_POSTGRES_SERVER_SCOPE_KEY];
|
|
131
|
+
if (dbServer && recorded[DESKTOP_AUTH_DB_SERVER_SCOPE_KEY] !== dbServer) {
|
|
132
|
+
reasons.push('database host changed');
|
|
133
|
+
}
|
|
117
134
|
if (!recorded[DESKTOP_AUTH_DEPLOYED_SCOPE_KEY])
|
|
118
135
|
reasons.push('never ran healthy');
|
|
119
136
|
if (redirect !== callback && !blocked)
|
package/dist/plan/executor.js
CHANGED
|
@@ -32,7 +32,7 @@ import { LOGIN_COOKIE_DOMAIN_SCOPE_KEY } from './cookie-domain.js';
|
|
|
32
32
|
import { previewsOn } from './coolify-previews.js';
|
|
33
33
|
import { CORE_FILES_COLLECTION_NAME, FILES_CORE_COLLECTION_SCOPE_KEY, ZITADEL_FILES_PROJECT_SCOPE_KEY, } from './core-files.js';
|
|
34
34
|
import { waitForDeploymentFinished, waitForHealthyVersion, waitForNewDeployment, } from './deploy-health.js';
|
|
35
|
-
import { DESKTOP_AUTH_APP_SCOPE_KEY, DESKTOP_AUTH_DEPLOYED_SCOPE_KEY, DESKTOP_AUTH_DOCKERFILE, DESKTOP_AUTH_HOME, DESKTOP_AUTH_ORIGIN_SCOPE_KEY, DESKTOP_AUTH_READY_PATH, DESKTOP_AUTH_READY_SCOPE_KEY, DESKTOP_AUTH_REDIRECT_SCOPE_KEY, DESKTOP_AUTH_REVISION_SCOPE_KEY, desktopAuthCallbackUri, desktopAuthEnv, desktopAuthInputs, desktopAuthRedirectUnsupported, desktopAuthRevision, } from './desktop-auth.js';
|
|
35
|
+
import { DESKTOP_AUTH_APP_SCOPE_KEY, DESKTOP_AUTH_DB_SERVER_SCOPE_KEY, DESKTOP_AUTH_DEPLOYED_SCOPE_KEY, DESKTOP_AUTH_DOCKERFILE, DESKTOP_AUTH_HOME, DESKTOP_AUTH_ORIGIN_SCOPE_KEY, DESKTOP_AUTH_READY_PATH, DESKTOP_AUTH_READY_SCOPE_KEY, DESKTOP_AUTH_REDIRECT_SCOPE_KEY, DESKTOP_AUTH_REVISION_SCOPE_KEY, desktopAuthCallbackUri, desktopAuthEnv, desktopAuthInputs, desktopAuthRedirectUnsupported, desktopAuthRevision, } from './desktop-auth.js';
|
|
36
36
|
import { desktopCallbackUri, signInCallbackAppliedValue, signInRedirectUris, unionRedirectUris, zitadelAppDesktopCallbackAppliedScopeKey, } from './desktop-callback.js';
|
|
37
37
|
import { PLATFORM_NETWORK, companyNetworkName, ensureDestination, findDestination, onPlatformNetwork, placed, placedByScope, placedOnPlatform, } from './destinations.js';
|
|
38
38
|
import { DEFAULT_AI_LIMIT_MICROS } from './diff.js';
|
|
@@ -7747,6 +7747,12 @@ export class FoundryStepExecutor {
|
|
|
7747
7747
|
await this.addDesktopAuthCallback(org, context, desktopAuthCallbackUri(inputs.origin));
|
|
7748
7748
|
context.recordScopeId(DESKTOP_AUTH_ORIGIN_SCOPE_KEY, inputs.origin);
|
|
7749
7749
|
context.recordScopeId(DESKTOP_AUTH_REVISION_SCOPE_KEY, desktopAuthRevision(env));
|
|
7750
|
+
// foundry#1112: the database host itself is not part of `env`'s revision (it comes from a live
|
|
7751
|
+
// Coolify read, not from `desktopAuthEnv`'s inputs), so the server this env was built against is
|
|
7752
|
+
// tracked here instead -- a later change replans this step even when nothing else drifted.
|
|
7753
|
+
const dbServerId = recorded[ORG_POSTGRES_SERVER_SCOPE_KEY];
|
|
7754
|
+
if (dbServerId)
|
|
7755
|
+
context.recordScopeId(DESKTOP_AUTH_DB_SERVER_SCOPE_KEY, dbServerId);
|
|
7750
7756
|
return { resourceId: app.appId };
|
|
7751
7757
|
}
|
|
7752
7758
|
/** Whether the org's running Agora carries `AGORA_DESKTOP_AUTH_UPSTREAM`, read from its live env. */
|
package/dist/plan/own-diff.js
CHANGED
|
@@ -13,7 +13,7 @@ import { ownHostnames, passkeyRpIdFor } from './own-hostnames.js';
|
|
|
13
13
|
import { JOBS_PUBLIC_URL_SCOPE_KEY, OWN_JOBS_ROUTE_TUNNEL_SCOPE_KEY } from './own-jobs-route.js';
|
|
14
14
|
import { OWN_FILES_R2_SCOPE_KEY, OWN_SERVICES_APPLIED_SCOPE_KEY, orgTarget, } from './own-services.js';
|
|
15
15
|
import { OWN_SFU_APPLIED_HOSTNAME_SCOPE_KEY, OWN_SFU_APPLIED_NODE_IP_SCOPE_KEY, OWN_SFU_APPLIED_SLOT_SCOPE_KEY, OWN_SFU_APPLIED_VERSION_SCOPE_KEY, OWN_SFU_DEPLOY_PENDING_SCOPE_KEY, OWN_SFU_KEYS_UNDELIVERED_SCOPE_KEY, SFU_INTERNAL_URL_SCOPE_KEY, SFU_PUBLIC_URL_SCOPE_KEY, } from './own-sfu.js';
|
|
16
|
-
import { AUTH_MCP_ENV_VERSION, AUTH_TUNNEL_ROUTES_VERSION, AUTH_ZITADEL_RUN_OPTIONS, JOBS_DEPLOY_PENDING_SCOPE_KEY, JOBS_INTERNAL_URL_SCOPE_KEY, PLATFORM_AUTH_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_ADMIN_USER_SCOPE_KEY, PLATFORM_AUTH_BROKER_DEPLOYED_SCOPE_KEY, PLATFORM_AUTH_BROKER_SCOPE_KEY, PLATFORM_AUTH_CONNECTOR_APP_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_LOGIN_CLIENT_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_LOGIN_CLIENT_USER_SCOPE_KEY, PLATFORM_AUTH_LOGIN_ENV_SCOPE_KEY, PLATFORM_AUTH_MCP_SCOPE_KEY, PLATFORM_AUTH_SMTP_SCOPE_KEY, PLATFORM_AUTH_TUNNEL_ROUTES_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_RUN_OPTIONS_SCOPE_KEY, PLATFORM_FILES_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_FILES_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_FILES_INTERNAL_URL_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_FILES_MANAGEMENT_UNDELIVERED_SCOPE_KEY, PLATFORM_MAIL_ADMIN_KEY_SCOPE_KEY, PLATFORM_MAIL_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_MAIL_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_MAIL_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY, authLoginEnvMarker, orgDeclaresMcp, platformMailMxHost, } from './platform-diff.js';
|
|
16
|
+
import { AUTH_ISSUER_SOURCE_ENV_VERSION, AUTH_MCP_ENV_VERSION, AUTH_TUNNEL_ROUTES_VERSION, AUTH_ZITADEL_RUN_OPTIONS, JOBS_DEPLOY_PENDING_SCOPE_KEY, JOBS_INTERNAL_URL_SCOPE_KEY, PLATFORM_AUTH_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_ADMIN_USER_SCOPE_KEY, PLATFORM_AUTH_BROKER_DEPLOYED_SCOPE_KEY, PLATFORM_AUTH_BROKER_SCOPE_KEY, PLATFORM_AUTH_CONNECTOR_APP_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_ISSUER_SOURCE_ENV_SCOPE_KEY, PLATFORM_AUTH_LOGIN_CLIENT_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_LOGIN_CLIENT_USER_SCOPE_KEY, PLATFORM_AUTH_LOGIN_ENV_SCOPE_KEY, PLATFORM_AUTH_MCP_SCOPE_KEY, PLATFORM_AUTH_SMTP_SCOPE_KEY, PLATFORM_AUTH_TUNNEL_ROUTES_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_RUN_OPTIONS_SCOPE_KEY, PLATFORM_FILES_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_FILES_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_FILES_INTERNAL_URL_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_FILES_MANAGEMENT_UNDELIVERED_SCOPE_KEY, PLATFORM_MAIL_ADMIN_KEY_SCOPE_KEY, PLATFORM_MAIL_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_MAIL_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_MAIL_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY, authLoginEnvMarker, orgDeclaresMcp, platformMailMxHost, } from './platform-diff.js';
|
|
17
17
|
import { OWN_FILES_RUNNER_SCOPE_KEY } from './platform-org.js';
|
|
18
18
|
import { JOBS_ADMIN_TOKEN_UNDELIVERED_SCOPE_KEY, JOBS_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_AUTH_DB_SCOPE_KEY, PLATFORM_AUTH_LOGIN_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_SCOPE_KEY, PLATFORM_FILES_SHARE_DOMAINS_SCOPE_KEY, filesShareDomains, } from './platform-providers.js';
|
|
19
19
|
import { SIGN_IN_LOGIN_APP_SCOPE_KEY, inAppSignIn, signInLoginNames } from './sign-in.js';
|
|
@@ -266,6 +266,8 @@ export function planOwnAuth(options) {
|
|
|
266
266
|
recordedIds[PLATFORM_AUTH_SMTP_SCOPE_KEY] &&
|
|
267
267
|
recordedIds[PLATFORM_AUTH_ZITADEL_RUN_OPTIONS_SCOPE_KEY] === AUTH_ZITADEL_RUN_OPTIONS &&
|
|
268
268
|
recordedIds[PLATFORM_AUTH_TUNNEL_ROUTES_SCOPE_KEY] === AUTH_TUNNEL_ROUTES_VERSION &&
|
|
269
|
+
// The login apps' source link settings; a stack from before them is written once.
|
|
270
|
+
recordedIds[PLATFORM_AUTH_ISSUER_SOURCE_ENV_SCOPE_KEY] === AUTH_ISSUER_SOURCE_ENV_VERSION &&
|
|
269
271
|
// The login apps' mail env (`LOGIN_MAIL_FROM`, the Lettermint key); a stack from before it is written again.
|
|
270
272
|
recordedIds[PLATFORM_AUTH_LOGIN_ENV_SCOPE_KEY] ===
|
|
271
273
|
authLoginEnvMarker(`noreply@${names.mailDomain}`, passkeyRpIdFor(org)) &&
|
|
@@ -86,6 +86,16 @@ export declare const AUTH_LOGIN_ENV_VERSION = "4";
|
|
|
86
86
|
export declare function authLoginEnvMarker(smtpSender: string, passkeyRpId?: string): string;
|
|
87
87
|
/** The {@link authLoginEnvMarker} the login apps' env was last written with, once live on them. */
|
|
88
88
|
export declare const PLATFORM_AUTH_LOGIN_ENV_SCOPE_KEY = "auth_login_env_applied";
|
|
89
|
+
/**
|
|
90
|
+
* The version of the two settings the sign-in app's source link reads (`ISSUER_SOURCE_URL`,
|
|
91
|
+
* `ISSUER_SOURCE_LINK_SECRET`). Raise it to write them again. They are kept apart from
|
|
92
|
+
* {@link AUTH_LOGIN_ENV_VERSION} on purpose: a change to the marker redeploys both login apps, and
|
|
93
|
+
* these two settings must not.
|
|
94
|
+
* 1: the login apps get both settings (foundry 0.76.0).
|
|
95
|
+
*/
|
|
96
|
+
export declare const AUTH_ISSUER_SOURCE_ENV_VERSION = "1";
|
|
97
|
+
/** The {@link AUTH_ISSUER_SOURCE_ENV_VERSION} the login apps' source link settings were last written with. */
|
|
98
|
+
export declare const PLATFORM_AUTH_ISSUER_SOURCE_ENV_SCOPE_KEY = "auth_issuer_source_env_applied";
|
|
89
99
|
/**
|
|
90
100
|
* `AUTH_MCP_ENV_VERSION` once the broker holds `MCP_DATABASE_URL`, `MCP_OAUTH_SECRET` and `AUTH_STATE_SECRET` (auth ADR 0002), recorded by the
|
|
91
101
|
* sign-in step when an entry of that broker declares `uses.auth.mcp`. A broker entry with `mcp` is not
|
|
@@ -95,6 +95,16 @@ export function authLoginEnvMarker(smtpSender, passkeyRpId) {
|
|
|
95
95
|
}
|
|
96
96
|
/** The {@link authLoginEnvMarker} the login apps' env was last written with, once live on them. */
|
|
97
97
|
export const PLATFORM_AUTH_LOGIN_ENV_SCOPE_KEY = 'auth_login_env_applied';
|
|
98
|
+
/**
|
|
99
|
+
* The version of the two settings the sign-in app's source link reads (`ISSUER_SOURCE_URL`,
|
|
100
|
+
* `ISSUER_SOURCE_LINK_SECRET`). Raise it to write them again. They are kept apart from
|
|
101
|
+
* {@link AUTH_LOGIN_ENV_VERSION} on purpose: a change to the marker redeploys both login apps, and
|
|
102
|
+
* these two settings must not.
|
|
103
|
+
* 1: the login apps get both settings (foundry 0.76.0).
|
|
104
|
+
*/
|
|
105
|
+
export const AUTH_ISSUER_SOURCE_ENV_VERSION = '1';
|
|
106
|
+
/** The {@link AUTH_ISSUER_SOURCE_ENV_VERSION} the login apps' source link settings were last written with. */
|
|
107
|
+
export const PLATFORM_AUTH_ISSUER_SOURCE_ENV_SCOPE_KEY = 'auth_issuer_source_env_applied';
|
|
98
108
|
/**
|
|
99
109
|
* `AUTH_MCP_ENV_VERSION` once the broker holds `MCP_DATABASE_URL`, `MCP_OAUTH_SECRET` and `AUTH_STATE_SECRET` (auth ADR 0002), recorded by the
|
|
100
110
|
* sign-in step when an entry of that broker declares `uses.auth.mcp`. A broker entry with `mcp` is not
|
|
@@ -2300,6 +2310,8 @@ function planAuth(platform, recordedIds, executorBlocked, executorMissing, authD
|
|
|
2300
2310
|
// step's redeploy, so a platform recorded before them still plans it.
|
|
2301
2311
|
recordedIds[PLATFORM_AUTH_ZITADEL_RUN_OPTIONS_SCOPE_KEY] === AUTH_ZITADEL_RUN_OPTIONS &&
|
|
2302
2312
|
recordedIds[PLATFORM_AUTH_TUNNEL_ROUTES_SCOPE_KEY] === AUTH_TUNNEL_ROUTES_VERSION &&
|
|
2313
|
+
// The login apps' source link settings: a platform from before them plans the step once.
|
|
2314
|
+
recordedIds[PLATFORM_AUTH_ISSUER_SOURCE_ENV_SCOPE_KEY] === AUTH_ISSUER_SOURCE_ENV_VERSION &&
|
|
2303
2315
|
// The login apps' mail env: a platform from before it, or with a new apex, is written again.
|
|
2304
2316
|
// Without the held key the apply cannot record it, so it is asked for only once the key is held.
|
|
2305
2317
|
(!mailKeyHeld ||
|
|
@@ -1420,6 +1420,22 @@ export declare function brokerDeployNeeded(missingInputs: readonly string[], bro
|
|
|
1420
1420
|
* wrote there. Paired with {@link brokerDeployNeeded}, which reads it back.
|
|
1421
1421
|
*/
|
|
1422
1422
|
export declare function brokerDeployRecordValue(brokerAppId: string, authAppsRaw: string | undefined): string;
|
|
1423
|
+
/**
|
|
1424
|
+
* The held master key of the sign-in app's source link: one value the platform holds. It is read in foundry
|
|
1425
|
+
* only and never reaches a container, plan line, log or error; each company gets a key derived from it
|
|
1426
|
+
* ({@link issuerSourceLinkKey}). Never minted here; a person (or the host) puts it under this ref, and a
|
|
1427
|
+
* missing value only hides the link.
|
|
1428
|
+
*/
|
|
1429
|
+
export declare const PLATFORM_AUTH_ISSUER_SOURCE_LINK_SECRET_REF = "issuer-source-link-secret";
|
|
1430
|
+
/** The sign-in app's source link settings. The URL is public; the key never reaches a plan line, log or error. */
|
|
1431
|
+
export declare const LOGIN_ISSUER_SOURCE_URL_ENV = "ISSUER_SOURCE_URL";
|
|
1432
|
+
export declare const LOGIN_ISSUER_SOURCE_LINK_SECRET_ENV = "ISSUER_SOURCE_LINK_SECRET";
|
|
1433
|
+
/** The company id of a source link: the target's id (`platform`, or the org's slug), the one its internal names use. */
|
|
1434
|
+
export declare const ISSUER_SOURCE_COMPANY_ID: RegExp;
|
|
1435
|
+
/** The source link of one company. */
|
|
1436
|
+
export declare function issuerSourceUrl(company: string): string;
|
|
1437
|
+
/** A company's source link key: lowercase hex of HMAC-SHA256(master, company). */
|
|
1438
|
+
export declare function issuerSourceLinkKey(master: string, company: string): string;
|
|
1423
1439
|
/** Whether any desired env is missing from the app, or set to another value. */
|
|
1424
1440
|
export declare function envsDiffer(coolify: Pick<CoolifyPort, 'listEnvs'>, appId: string, desired: Array<{
|
|
1425
1441
|
key: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createHash, createPrivateKey, generateKeyPairSync, randomBytes, randomUUID, sign, } from 'node:crypto';
|
|
1
|
+
import { createHash, createHmac, createPrivateKey, generateKeyPairSync, randomBytes, randomUUID, sign, } from 'node:crypto';
|
|
2
2
|
import { isIPv4 } from 'node:net';
|
|
3
3
|
import { applyObjects, openInstance, platformMailSettingsObjects } from '@wtfalch/email/postmaster';
|
|
4
4
|
import { VERSIONS, coolifyImageFor, floatingTagBlocked, pinnedRef } from '../bootstrap/versions.js';
|
|
@@ -34,7 +34,7 @@ import { MAIL_APP_SCOPE_KEY, MAIL_DATABASE_NAME, MAIL_DATABASE_PASSWORD_ENV, MAI
|
|
|
34
34
|
import { OIKOS_INGRESS_BLOCKED, PLATFORM_OIKOS_INGRESS_KEY, oikosIngressApplied, oikosIngressZoneBlocked, provisionOikosIngress, } from './oikos-ingress.js';
|
|
35
35
|
import { recordOwnDnsHostname } from './own-dns.js';
|
|
36
36
|
import { platformNetwork, platformTarget, scopeFromPlatform, } from './own-services.js';
|
|
37
|
-
import { AUTH_MCP_ENV_VERSION, AUTH_TUNNEL_ROUTES_VERSION, AUTH_ZITADEL_RUN_OPTIONS, GITHUB_RELEASE_HOOK_DEPS_MISSING, GITHUB_RELEASE_WEBHOOK_SECRET_ENV, JOBS_DEPLOY_PENDING_SCOPE_KEY, JOBS_INTERNAL_URL_SCOPE_KEY, JOBS_SCHEDULER_KEY, PLATFORM_ACCESS_PROVIDER_APPLIED_AUTH_DOMAIN_SCOPE_KEY, PLATFORM_ACCESS_PROVIDER_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_ACCESS_PROVIDER_UNDELIVERED_SCOPE_KEY, PLATFORM_ACCESS_ZITADEL_APP_SCOPE_KEY, PLATFORM_ACCESS_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_AI_APPLIED_GITREF_SCOPE_KEY, PLATFORM_AI_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_AI_CONNECTOR_APP_SCOPE_KEY, PLATFORM_AI_DEPLOY_PENDING_SCOPE_KEY, PLATFORM_AI_INTERNAL_URL_SCOPE_KEY, PLATFORM_AI_KEY, PLATFORM_AI_MANAGEMENT_KEY_CONFLICT_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_AI_MIGRATE_BLOCKED_SCOPE_KEY, PLATFORM_AI_ORGANISATION_SCOPE_KEY, PLATFORM_AI_SIGNING_KEY_SET_SCOPE_KEY, PLATFORM_AI_SIGNING_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_AI_TUNNEL_SCOPE_KEY, PLATFORM_ARCHON_ACCESS_PIN_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_AUTH_HOSTNAME_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_AUTH_ORG_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_BROKER_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_CI_ORG_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_FILES_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_FIRST_OWNER_LINK_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_ROLLING_UPDATE_SCOPE_KEY, PLATFORM_ARCHON_APP_KEY_ORG_SCOPE_KEY, PLATFORM_ARCHON_CONNECTOR_APP_SCOPE_KEY, PLATFORM_ARCHON_COOLIFY_READ_TOKEN_REF, PLATFORM_ARCHON_DEPLOYMENT_SCOPE_KEY, PLATFORM_ARCHON_DESKTOP_CALLBACK_APPLIED_SCOPE_KEY, PLATFORM_ARCHON_ENVS_DEPLOYED_SCOPE_KEY, PLATFORM_ARCHON_GATE_CLOSED_SCOPE_KEY, PLATFORM_ARCHON_ID_TOKEN_USERINFO_APPLIED_SCOPE_KEY, PLATFORM_ARCHON_INTEGRATIONS_KEY_SYNCED_SCOPE_KEY, PLATFORM_ARCHON_KEY, PLATFORM_ARCHON_MASTER_CLOUDFLARE_TOKEN_REF, PLATFORM_ARCHON_MASTER_COOLIFY_TOKEN_REF, PLATFORM_ARCHON_MASTER_COOLIFY_URL_REF, PLATFORM_ARCHON_ORG_DOMAIN_BLOCKED_SCOPE_KEY, PLATFORM_ARCHON_ORG_DOMAIN_SCOPE_KEY, PLATFORM_ARCHON_ORG_POLICY_SCOPE_KEY, PLATFORM_ARCHON_ORG_REGISTRATION_CLOSED_SCOPE_KEY, PLATFORM_ARCHON_ORG_SCOPE_KEY, PLATFORM_ARCHON_OWNER_INVITE_ORG_SCOPE_KEY, PLATFORM_ARCHON_OWNER_INVITE_SCOPE_KEY, PLATFORM_ARCHON_POST_LOGOUT_APPLIED_SCOPE_KEY, PLATFORM_ARCHON_RETIRED_CLIENT_SCOPE_KEY, PLATFORM_ARCHON_UPTIME_TICKS_SYNCED_SCOPE_KEY, PLATFORM_ARCHON_UPTIME_TOKEN_SYNCED_SCOPE_KEY, PLATFORM_ARCHON_WEBHOOK_SECRET_DEPLOYED_SCOPE_KEY, PLATFORM_ARCHON_ZITADEL_APP_SCOPE_KEY, PLATFORM_ARCHON_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_AUTH_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_ADMIN_USER_SCOPE_KEY, PLATFORM_AUTH_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_AUTH_BROKER_DEPLOYED_SCOPE_KEY, PLATFORM_AUTH_BROKER_SCOPE_KEY, PLATFORM_AUTH_CONNECTOR_APP_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_KEY, PLATFORM_AUTH_LOGIN_CLIENT_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_LOGIN_CLIENT_USER_SCOPE_KEY, PLATFORM_AUTH_LOGIN_ENV_SCOPE_KEY, PLATFORM_AUTH_MCP_SCOPE_KEY, PLATFORM_AUTH_OWNER_INVITE_ORG_SCOPE_KEY, PLATFORM_AUTH_OWNER_INVITE_SCOPE_KEY, PLATFORM_AUTH_REGISTRATION_CLOSED_SCOPE_KEY, PLATFORM_AUTH_RESERVED_ADMIN_USERNAME_SCOPE_KEY, PLATFORM_AUTH_SMTP_SCOPE_KEY, PLATFORM_AUTH_TUNNEL_ROUTES_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_APPLIED_IMAGE_TAG_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_RUN_OPTIONS_SCOPE_KEY, PLATFORM_BACKUP_DATABASE_SCOPE_KEYS, PLATFORM_BACKUP_SERVICE_KEYS, PLATFORM_EDGE_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_EDGE_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_EDGE_APPLIED_USAGE_TAIL_SCOPE_KEY, PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF, PLATFORM_EDGE_INTERNAL_URL_SCOPE_KEY, PLATFORM_EDGE_KEY, PLATFORM_EDGE_KEY_REF, PLATFORM_EDGE_PLATFORM_KEY_SET_SCOPE_KEY, PLATFORM_EDGE_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_FILES_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_FILES_INTERNAL_URL_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_KEY, PLATFORM_FILES_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_FILES_MANAGEMENT_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_GITHUB_RELEASE_HOOK_KEY, PLATFORM_HC_ACCESS_SCOPE_KEY, PLATFORM_HC_API_KEY_REF, PLATFORM_HC_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_HC_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_HC_KEY, PLATFORM_HEARTBEATS_APPLIED_SCOPE_KEY, PLATFORM_HEARTBEATS_HOSTED_API_KEY_REF, PLATFORM_INTEGRATIONS_APPLIED_GITREF_SCOPE_KEY, PLATFORM_INTEGRATIONS_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY, PLATFORM_INTEGRATIONS_KEY_ID_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_ROTATION_PREVIOUS_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_ROTATION_REQUESTED_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_ROTATION_UNDELIVERED_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_SET_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_INTEGRATIONS_RUNNER_KEYRING_DEPLOYED_SCOPE_KEY, PLATFORM_MAIL_ADMIN_KEY_SCOPE_KEY, PLATFORM_MAIL_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_MAIL_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_MAIL_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_MAIL_CONNECTOR_APP_SCOPE_KEY, PLATFORM_MAIL_HOST_PORTS_DIRECT, PLATFORM_MAIL_HOST_PORTS_SCOPE_KEY, PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY, PLATFORM_MAIL_KEY, PLATFORM_MAIL_RELAY_KEY, PLATFORM_MAIL_ROLE_CHECK_SCOPE_KEY, PLATFORM_MAIL_ROLE_ENSURED_SCOPE_KEY, PLATFORM_MAIL_ROLE_GRANTED_SCOPE_KEY, PLATFORM_MAIL_ROUTE_SCOPE_KEY, PLATFORM_MAIL_ROUTE_WANTED, PLATFORM_MAIL_USER_ROLE, PLATFORM_MAIL_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_OWNER_ORG_DOMAIN_BLOCKED_SCOPE_KEY, PLATFORM_OWNER_ORG_DOMAIN_SCOPE_KEY, PLATFORM_OWNER_ORG_SCOPE_KEY, PLATFORM_SFU_APPLIED_SCOPE_KEY, PLATFORM_UPTIME_ACCESS_CLIENT_ID_REF, PLATFORM_UPTIME_ACCESS_CLIENT_SECRET_REF, PLATFORM_UPTIME_ACCESS_TOKEN_ID_SCOPE_KEY, PLATFORM_UPTIME_ACCESS_TOKEN_NAME, PLATFORM_UPTIME_ACCESS_UNDELIVERED_SCOPE_KEY, PLATFORM_UPTIME_AUDIT_SEAL_TICK_ID_SCOPE_KEY, PLATFORM_UPTIME_AUDIT_SEAL_TICK_TOKEN_REF, PLATFORM_UPTIME_CHAT_ROOM_ID_SCOPE_KEY, PLATFORM_UPTIME_HEARTBEAT_CHECK_NAME, PLATFORM_UPTIME_KEY, PLATFORM_UPTIME_RELEASE_TICK_ID_SCOPE_KEY, PLATFORM_UPTIME_RELEASE_TICK_TOKEN_REF, PLATFORM_UPTIME_REMOVED_SCOPE_KEY, PLATFORM_UPTIME_SCRIPT_NAME, PLATFORM_UPTIME_TOKEN_ID_SCOPE_KEY, PLATFORM_UPTIME_TOKEN_REF, PLATFORM_USAGE_TAIL_KEY, PLATFORM_USAGE_TAIL_REMOVED_SCOPE_KEY, PLATFORM_USAGE_TAIL_SCRIPT_NAME, PLATFORM_ZITADEL_ORG_SCOPE_KEY, archonFilesMarker, archonFirstOwnerLink, archonOrgDomain, archonOrgName, authLoginEnvMarker, desiredHeartbeatCheckNames, heartbeatCheckUrlRef, orgDeclaresMcp, parseBrokerDeployRecord, parseLoginClientRecord, platformBackupHeartbeatCheckName, platformMailHostPorts, platformMailMxHost, uptimeAccessTokenConflict, uptimeEffectiveVars, uptimeRecorded, uptimeTicksSyncValue, uptimeVarsDigest, usageTailEdgeEnv, usageTailEdgeEnvValue, usageTailRecorded, } from './platform-diff.js';
|
|
37
|
+
import { AUTH_ISSUER_SOURCE_ENV_VERSION, AUTH_MCP_ENV_VERSION, AUTH_TUNNEL_ROUTES_VERSION, AUTH_ZITADEL_RUN_OPTIONS, GITHUB_RELEASE_HOOK_DEPS_MISSING, GITHUB_RELEASE_WEBHOOK_SECRET_ENV, JOBS_DEPLOY_PENDING_SCOPE_KEY, JOBS_INTERNAL_URL_SCOPE_KEY, JOBS_SCHEDULER_KEY, PLATFORM_ACCESS_PROVIDER_APPLIED_AUTH_DOMAIN_SCOPE_KEY, PLATFORM_ACCESS_PROVIDER_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_ACCESS_PROVIDER_UNDELIVERED_SCOPE_KEY, PLATFORM_ACCESS_ZITADEL_APP_SCOPE_KEY, PLATFORM_ACCESS_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_AI_APPLIED_GITREF_SCOPE_KEY, PLATFORM_AI_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_AI_CONNECTOR_APP_SCOPE_KEY, PLATFORM_AI_DEPLOY_PENDING_SCOPE_KEY, PLATFORM_AI_INTERNAL_URL_SCOPE_KEY, PLATFORM_AI_KEY, PLATFORM_AI_MANAGEMENT_KEY_CONFLICT_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_AI_MIGRATE_BLOCKED_SCOPE_KEY, PLATFORM_AI_ORGANISATION_SCOPE_KEY, PLATFORM_AI_SIGNING_KEY_SET_SCOPE_KEY, PLATFORM_AI_SIGNING_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_AI_TUNNEL_SCOPE_KEY, PLATFORM_ARCHON_ACCESS_PIN_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_AUTH_HOSTNAME_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_AUTH_ORG_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_BROKER_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_CI_ORG_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_FILES_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_FIRST_OWNER_LINK_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_ROLLING_UPDATE_SCOPE_KEY, PLATFORM_ARCHON_APP_KEY_ORG_SCOPE_KEY, PLATFORM_ARCHON_CONNECTOR_APP_SCOPE_KEY, PLATFORM_ARCHON_COOLIFY_READ_TOKEN_REF, PLATFORM_ARCHON_DEPLOYMENT_SCOPE_KEY, PLATFORM_ARCHON_DESKTOP_CALLBACK_APPLIED_SCOPE_KEY, PLATFORM_ARCHON_ENVS_DEPLOYED_SCOPE_KEY, PLATFORM_ARCHON_GATE_CLOSED_SCOPE_KEY, PLATFORM_ARCHON_ID_TOKEN_USERINFO_APPLIED_SCOPE_KEY, PLATFORM_ARCHON_INTEGRATIONS_KEY_SYNCED_SCOPE_KEY, PLATFORM_ARCHON_KEY, PLATFORM_ARCHON_MASTER_CLOUDFLARE_TOKEN_REF, PLATFORM_ARCHON_MASTER_COOLIFY_TOKEN_REF, PLATFORM_ARCHON_MASTER_COOLIFY_URL_REF, PLATFORM_ARCHON_ORG_DOMAIN_BLOCKED_SCOPE_KEY, PLATFORM_ARCHON_ORG_DOMAIN_SCOPE_KEY, PLATFORM_ARCHON_ORG_POLICY_SCOPE_KEY, PLATFORM_ARCHON_ORG_REGISTRATION_CLOSED_SCOPE_KEY, PLATFORM_ARCHON_ORG_SCOPE_KEY, PLATFORM_ARCHON_OWNER_INVITE_ORG_SCOPE_KEY, PLATFORM_ARCHON_OWNER_INVITE_SCOPE_KEY, PLATFORM_ARCHON_POST_LOGOUT_APPLIED_SCOPE_KEY, PLATFORM_ARCHON_RETIRED_CLIENT_SCOPE_KEY, PLATFORM_ARCHON_UPTIME_TICKS_SYNCED_SCOPE_KEY, PLATFORM_ARCHON_UPTIME_TOKEN_SYNCED_SCOPE_KEY, PLATFORM_ARCHON_WEBHOOK_SECRET_DEPLOYED_SCOPE_KEY, PLATFORM_ARCHON_ZITADEL_APP_SCOPE_KEY, PLATFORM_ARCHON_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_AUTH_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_ADMIN_USER_SCOPE_KEY, PLATFORM_AUTH_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_AUTH_BROKER_DEPLOYED_SCOPE_KEY, PLATFORM_AUTH_BROKER_SCOPE_KEY, PLATFORM_AUTH_CONNECTOR_APP_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_ISSUER_SOURCE_ENV_SCOPE_KEY, PLATFORM_AUTH_KEY, PLATFORM_AUTH_LOGIN_CLIENT_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_LOGIN_CLIENT_USER_SCOPE_KEY, PLATFORM_AUTH_LOGIN_ENV_SCOPE_KEY, PLATFORM_AUTH_MCP_SCOPE_KEY, PLATFORM_AUTH_OWNER_INVITE_ORG_SCOPE_KEY, PLATFORM_AUTH_OWNER_INVITE_SCOPE_KEY, PLATFORM_AUTH_REGISTRATION_CLOSED_SCOPE_KEY, PLATFORM_AUTH_RESERVED_ADMIN_USERNAME_SCOPE_KEY, PLATFORM_AUTH_SMTP_SCOPE_KEY, PLATFORM_AUTH_TUNNEL_ROUTES_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_APPLIED_IMAGE_TAG_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_RUN_OPTIONS_SCOPE_KEY, PLATFORM_BACKUP_DATABASE_SCOPE_KEYS, PLATFORM_BACKUP_SERVICE_KEYS, PLATFORM_EDGE_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_EDGE_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_EDGE_APPLIED_USAGE_TAIL_SCOPE_KEY, PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF, PLATFORM_EDGE_INTERNAL_URL_SCOPE_KEY, PLATFORM_EDGE_KEY, PLATFORM_EDGE_KEY_REF, PLATFORM_EDGE_PLATFORM_KEY_SET_SCOPE_KEY, PLATFORM_EDGE_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_FILES_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_FILES_INTERNAL_URL_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_KEY, PLATFORM_FILES_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_FILES_MANAGEMENT_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_GITHUB_RELEASE_HOOK_KEY, PLATFORM_HC_ACCESS_SCOPE_KEY, PLATFORM_HC_API_KEY_REF, PLATFORM_HC_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_HC_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_HC_KEY, PLATFORM_HEARTBEATS_APPLIED_SCOPE_KEY, PLATFORM_HEARTBEATS_HOSTED_API_KEY_REF, PLATFORM_INTEGRATIONS_APPLIED_GITREF_SCOPE_KEY, PLATFORM_INTEGRATIONS_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY, PLATFORM_INTEGRATIONS_KEY_ID_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_ROTATION_PREVIOUS_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_ROTATION_REQUESTED_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_ROTATION_UNDELIVERED_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_SET_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_INTEGRATIONS_RUNNER_KEYRING_DEPLOYED_SCOPE_KEY, PLATFORM_MAIL_ADMIN_KEY_SCOPE_KEY, PLATFORM_MAIL_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_MAIL_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_MAIL_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_MAIL_CONNECTOR_APP_SCOPE_KEY, PLATFORM_MAIL_HOST_PORTS_DIRECT, PLATFORM_MAIL_HOST_PORTS_SCOPE_KEY, PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY, PLATFORM_MAIL_KEY, PLATFORM_MAIL_RELAY_KEY, PLATFORM_MAIL_ROLE_CHECK_SCOPE_KEY, PLATFORM_MAIL_ROLE_ENSURED_SCOPE_KEY, PLATFORM_MAIL_ROLE_GRANTED_SCOPE_KEY, PLATFORM_MAIL_ROUTE_SCOPE_KEY, PLATFORM_MAIL_ROUTE_WANTED, PLATFORM_MAIL_USER_ROLE, PLATFORM_MAIL_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_OWNER_ORG_DOMAIN_BLOCKED_SCOPE_KEY, PLATFORM_OWNER_ORG_DOMAIN_SCOPE_KEY, PLATFORM_OWNER_ORG_SCOPE_KEY, PLATFORM_SFU_APPLIED_SCOPE_KEY, PLATFORM_UPTIME_ACCESS_CLIENT_ID_REF, PLATFORM_UPTIME_ACCESS_CLIENT_SECRET_REF, PLATFORM_UPTIME_ACCESS_TOKEN_ID_SCOPE_KEY, PLATFORM_UPTIME_ACCESS_TOKEN_NAME, PLATFORM_UPTIME_ACCESS_UNDELIVERED_SCOPE_KEY, PLATFORM_UPTIME_AUDIT_SEAL_TICK_ID_SCOPE_KEY, PLATFORM_UPTIME_AUDIT_SEAL_TICK_TOKEN_REF, PLATFORM_UPTIME_CHAT_ROOM_ID_SCOPE_KEY, PLATFORM_UPTIME_HEARTBEAT_CHECK_NAME, PLATFORM_UPTIME_KEY, PLATFORM_UPTIME_RELEASE_TICK_ID_SCOPE_KEY, PLATFORM_UPTIME_RELEASE_TICK_TOKEN_REF, PLATFORM_UPTIME_REMOVED_SCOPE_KEY, PLATFORM_UPTIME_SCRIPT_NAME, PLATFORM_UPTIME_TOKEN_ID_SCOPE_KEY, PLATFORM_UPTIME_TOKEN_REF, PLATFORM_USAGE_TAIL_KEY, PLATFORM_USAGE_TAIL_REMOVED_SCOPE_KEY, PLATFORM_USAGE_TAIL_SCRIPT_NAME, PLATFORM_ZITADEL_ORG_SCOPE_KEY, archonFilesMarker, archonFirstOwnerLink, archonOrgDomain, archonOrgName, authLoginEnvMarker, desiredHeartbeatCheckNames, heartbeatCheckUrlRef, orgDeclaresMcp, parseBrokerDeployRecord, parseLoginClientRecord, platformBackupHeartbeatCheckName, platformMailHostPorts, platformMailMxHost, uptimeAccessTokenConflict, uptimeEffectiveVars, uptimeRecorded, uptimeTicksSyncValue, uptimeVarsDigest, usageTailEdgeEnv, usageTailEdgeEnvValue, usageTailRecorded, } from './platform-diff.js';
|
|
38
38
|
import { PLATFORM_REGISTRY_KEY, PLATFORM_REGISTRY_LOGINS_KEY, PLATFORM_REGISTRY_PASSWORDS_SET_SCOPE_KEY, PLATFORM_REGISTRY_PULL_PASSWORD_REF, registryImageTagBlocked, } from './platform-registry-keys.js';
|
|
39
39
|
import { ensureRegistryLogins, provisionPlatformRegistry, registryLoginsDrifted, } from './platform-registry.js';
|
|
40
40
|
import { PLATFORM_ARCHON_IN_APP_SCOPE_KEY, archonInAppBack, archonInAppBind, archonInAppHost, archonInAppPoint, archonInAppUnbind, } from './sign-in-archon.js';
|
|
@@ -1504,8 +1504,8 @@ export const PLATFORM_AUTH_PROJECT = 'platform';
|
|
|
1504
1504
|
* header and so cannot give two different apps the same public hostname.
|
|
1505
1505
|
*/
|
|
1506
1506
|
export const PLATFORM_AUTH_LOGIN_INTERNAL_NAME = 'platform-auth-login';
|
|
1507
|
-
/**
|
|
1508
|
-
const AUTH_ZITADEL_IMAGE = 'ghcr.io/
|
|
1507
|
+
/** The patched sign-in server (stock ZITADEL plus our patches; it keeps `/app/zitadel`). Private package: the Coolify server pulls it with its own login. Pinned in `versions.json` (#247). */
|
|
1508
|
+
const AUTH_ZITADEL_IMAGE = 'ghcr.io/wtfalch/auth-issuer';
|
|
1509
1509
|
const AUTH_ZITADEL_IMAGE_TAG = VERSIONS.zitadel;
|
|
1510
1510
|
/** `wtfalch/auth`'s own `login/Dockerfile` -- `docs/deploy.md`'s "One compose service, four containers... Two images are built from this repository: the proxy... and the login". */
|
|
1511
1511
|
const AUTH_REPO = 'wtfalch/auth';
|
|
@@ -2264,6 +2264,36 @@ export async function provisionAuthStack(scope, deps, target, input) {
|
|
|
2264
2264
|
loginEnvs.push({ key: 'LOGIN_MAIL_FROM', value: input.smtpSender });
|
|
2265
2265
|
if (input.passkeyRpId)
|
|
2266
2266
|
loginEnvs.push({ key: LOGIN_PASSKEY_RP_ID_ENV, value: input.passkeyRpId });
|
|
2267
|
+
// The sign-in app's source link: both settings, or neither. A master that is not held, or cannot be read,
|
|
2268
|
+
// hides the link and fails nothing; the marker stays unset, so the step is planned again once it is held.
|
|
2269
|
+
let issuerSourceSecret = null;
|
|
2270
|
+
let issuerSourceReadFailed = false;
|
|
2271
|
+
try {
|
|
2272
|
+
issuerSourceSecret =
|
|
2273
|
+
(await deps.heldKeys?.resolve(PLATFORM_AUTH_ISSUER_SOURCE_LINK_SECRET_REF)) ?? null;
|
|
2274
|
+
}
|
|
2275
|
+
catch {
|
|
2276
|
+
// No cause in the line: a failed read can carry anything.
|
|
2277
|
+
issuerSourceReadFailed = true;
|
|
2278
|
+
}
|
|
2279
|
+
let issuerSourceWritten = false;
|
|
2280
|
+
if (issuerSourceSecret && !ISSUER_SOURCE_COMPANY_ID.test(target.id)) {
|
|
2281
|
+
console.info(`${label}: ${target.id} is not a valid source link company id, so the sign-in app hides the source link`);
|
|
2282
|
+
}
|
|
2283
|
+
else if (issuerSourceSecret) {
|
|
2284
|
+
// The master key stays in foundry: the container gets a key derived for this company only.
|
|
2285
|
+
runtime.onSecret?.(issuerSourceSecret);
|
|
2286
|
+
const companyKey = issuerSourceLinkKey(issuerSourceSecret, target.id);
|
|
2287
|
+
runtime.onSecret?.(companyKey);
|
|
2288
|
+
loginEnvs.push({ key: LOGIN_ISSUER_SOURCE_URL_ENV, value: issuerSourceUrl(target.id) }, { key: LOGIN_ISSUER_SOURCE_LINK_SECRET_ENV, value: companyKey });
|
|
2289
|
+
issuerSourceWritten = true;
|
|
2290
|
+
}
|
|
2291
|
+
else if (issuerSourceReadFailed) {
|
|
2292
|
+
console.info(`${label}: reading the held key ${PLATFORM_AUTH_ISSUER_SOURCE_LINK_SECRET_REF} failed, so the sign-in app hides the source link for now`);
|
|
2293
|
+
}
|
|
2294
|
+
else {
|
|
2295
|
+
console.info(`${label}: the held key ${PLATFORM_AUTH_ISSUER_SOURCE_LINK_SECRET_REF} is not held, so the sign-in app hides the source link`);
|
|
2296
|
+
}
|
|
2267
2297
|
// `AUTH_APPS` and `ZITADEL_SERVICE_USER_TOKEN`/`_FILE` are not pushed here
|
|
2268
2298
|
// -- this function's own doc comment, "Known gaps". `LETTERMINT_API_TOKEN`
|
|
2269
2299
|
// is, once held (#210): pushing it costs nothing even while the broker
|
|
@@ -2300,7 +2330,7 @@ export async function provisionAuthStack(scope, deps, target, input) {
|
|
|
2300
2330
|
// container on its next deploy (`diff.ts`'s `coolifyCalls` follows the
|
|
2301
2331
|
// identical rule).
|
|
2302
2332
|
const zitadelEnvsChanged = await envsDiffer(deps.coolify, zitadelAppId, zitadelEnvs);
|
|
2303
|
-
const loginEnvsChanged = await envsDiffer(deps.coolify, loginAppId, loginEnvs);
|
|
2333
|
+
const loginEnvsChanged = await envsDiffer(deps.coolify, loginAppId, withoutIssuerSourceEnvs(loginEnvs));
|
|
2304
2334
|
const brokerEnvsChanged = await envsDiffer(deps.coolify, brokerAppId, brokerEnvs);
|
|
2305
2335
|
await deps.coolify.bulkUpsertEnvs(zitadelAppId, zitadelEnvs);
|
|
2306
2336
|
await deps.coolify.bulkUpsertEnvs(loginAppId, loginEnvs);
|
|
@@ -2332,7 +2362,7 @@ export async function provisionAuthStack(scope, deps, target, input) {
|
|
|
2332
2362
|
{ key: SIGN_IN_BIND_KEY_ENV, value: bindKey },
|
|
2333
2363
|
...(bindings ? [{ key: LOGIN_HOST_BINDINGS_ENV, value: bindings }] : []),
|
|
2334
2364
|
];
|
|
2335
|
-
signInEnvsChanged = await envsDiffer(deps.coolify, signInApp.appId, signInEnvs);
|
|
2365
|
+
signInEnvsChanged = await envsDiffer(deps.coolify, signInApp.appId, withoutIssuerSourceEnvs(signInEnvs));
|
|
2336
2366
|
await deps.coolify.bulkUpsertEnvs(signInApp.appId, signInEnvs);
|
|
2337
2367
|
staleRpIdSignIn = input.passkeyRpId
|
|
2338
2368
|
? false
|
|
@@ -2388,6 +2418,11 @@ export async function provisionAuthStack(scope, deps, target, input) {
|
|
|
2388
2418
|
if (input.signInLogin)
|
|
2389
2419
|
await record(SIGN_IN_BIND_KEY_SCOPE_KEY, '1');
|
|
2390
2420
|
}
|
|
2421
|
+
// The source link settings are written on both login apps and need no deploy of their own. Recorded only
|
|
2422
|
+
// when they were written, so a company without the master is planned again once it is held.
|
|
2423
|
+
if (issuerSourceWritten) {
|
|
2424
|
+
await record(PLATFORM_AUTH_ISSUER_SOURCE_ENV_SCOPE_KEY, AUTH_ISSUER_SOURCE_ENV_VERSION);
|
|
2425
|
+
}
|
|
2391
2426
|
// The mail env is live on the login apps: written above and deployed with them. Without the held
|
|
2392
2427
|
// key the marker stays unset, so the step is planned again once the key is held.
|
|
2393
2428
|
if (heldMailKey && input.smtpSender) {
|
|
@@ -7653,6 +7688,33 @@ export function brokerDeployRecordValue(brokerAppId, authAppsRaw) {
|
|
|
7653
7688
|
return JSON.stringify(record);
|
|
7654
7689
|
}
|
|
7655
7690
|
const LOGIN_PASSKEY_RP_ID_ENV = 'LOGIN_PASSKEY_RP_ID';
|
|
7691
|
+
/**
|
|
7692
|
+
* The held master key of the sign-in app's source link: one value the platform holds. It is read in foundry
|
|
7693
|
+
* only and never reaches a container, plan line, log or error; each company gets a key derived from it
|
|
7694
|
+
* ({@link issuerSourceLinkKey}). Never minted here; a person (or the host) puts it under this ref, and a
|
|
7695
|
+
* missing value only hides the link.
|
|
7696
|
+
*/
|
|
7697
|
+
export const PLATFORM_AUTH_ISSUER_SOURCE_LINK_SECRET_REF = 'issuer-source-link-secret';
|
|
7698
|
+
/** The sign-in app's source link settings. The URL is public; the key never reaches a plan line, log or error. */
|
|
7699
|
+
export const LOGIN_ISSUER_SOURCE_URL_ENV = 'ISSUER_SOURCE_URL';
|
|
7700
|
+
export const LOGIN_ISSUER_SOURCE_LINK_SECRET_ENV = 'ISSUER_SOURCE_LINK_SECRET';
|
|
7701
|
+
/** The company id of a source link: the target's id (`platform`, or the org's slug), the one its internal names use. */
|
|
7702
|
+
export const ISSUER_SOURCE_COMPANY_ID = /^[a-z0-9][a-z0-9_-]{0,62}$/;
|
|
7703
|
+
/** The source link of one company. */
|
|
7704
|
+
export function issuerSourceUrl(company) {
|
|
7705
|
+
return `https://auth-issuer-source.wtfalch-business.workers.dev/c/${company}/sha256/1bc635d35b65f87d8c3224d76aecf301cb01730cd31e1612a5e4e6f78a8d59ed/auth-issuer-source.tar.gz`;
|
|
7706
|
+
}
|
|
7707
|
+
/** A company's source link key: lowercase hex of HMAC-SHA256(master, company). */
|
|
7708
|
+
export function issuerSourceLinkKey(master, company) {
|
|
7709
|
+
return createHmac('sha256', master).update(company).digest('hex');
|
|
7710
|
+
}
|
|
7711
|
+
/**
|
|
7712
|
+
* Drops the source link settings from an env list before it is compared with the live env. Changing them
|
|
7713
|
+
* must not redeploy a login app: they reach a running app on its next deploy, and a new app gets them at create.
|
|
7714
|
+
*/
|
|
7715
|
+
function withoutIssuerSourceEnvs(envs) {
|
|
7716
|
+
return envs.filter((e) => e.key !== LOGIN_ISSUER_SOURCE_URL_ENV && e.key !== LOGIN_ISSUER_SOURCE_LINK_SECRET_ENV);
|
|
7717
|
+
}
|
|
7656
7718
|
/** Removes one env from an app when it is live. True when it was removed; false with nothing live or no delete on the port. */
|
|
7657
7719
|
async function removeLoginEnv(coolify, appId, key) {
|
|
7658
7720
|
if (typeof coolify.deleteEnv !== 'function')
|
package/package.json
CHANGED
package/versions.digests.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"zitadel": "sha256:
|
|
2
|
+
"zitadel": "sha256:67af7d205cbbae4c60ce90c5034521fbb73a711a49bffec6aa719927ca77a14f",
|
|
3
3
|
"synapse": "sha256:6b95dd129e35e97e8032cb759e5db4a516a5f7ef6c98d34d716fea1ae239b62a",
|
|
4
4
|
"mas": "sha256:52c18ffcc940220a3b6aa5985b7e09d24ac27f5ed10a4d660c312e48f73ff105",
|
|
5
5
|
"livekit": "sha256:6fd3b7088874c4d119160dd688798dfec852bc014786d392caad15f6f63912a3",
|
package/versions.json
CHANGED