@noodleseed/one 0.165.0 → 0.167.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/dist/commands/author-loop.d.ts.map +1 -1
- package/dist/commands/author-loop.js +18 -3
- package/dist/commands/author-loop.js.map +1 -1
- package/dist/commands/deploy-ops.d.ts.map +1 -1
- package/dist/commands/deploy-ops.js +21 -2
- package/dist/commands/deploy-ops.js.map +1 -1
- package/dist/commands/deploy-status-ops.d.ts +2 -0
- package/dist/commands/deploy-status-ops.d.ts.map +1 -1
- package/dist/commands/deploy-status-ops.js +27 -0
- package/dist/commands/deploy-status-ops.js.map +1 -1
- package/dist/control-plane-request.d.ts +2 -0
- package/dist/control-plane-request.d.ts.map +1 -1
- package/dist/control-plane-request.js +18 -0
- package/dist/control-plane-request.js.map +1 -1
- package/dist/deploy.d.ts +2 -1
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +15 -0
- package/dist/deploy.js.map +1 -1
- package/dist/dev.d.ts +2 -0
- package/dist/dev.d.ts.map +1 -1
- package/dist/dev.js +12 -1
- package/dist/dev.js.map +1 -1
- package/dist/devtools-auth-session.d.ts +5 -0
- package/dist/devtools-auth-session.d.ts.map +1 -1
- package/dist/devtools-auth-session.js +41 -2
- package/dist/devtools-auth-session.js.map +1 -1
- package/dist/devtools-auth-types.d.ts +2 -1
- package/dist/devtools-auth-types.d.ts.map +1 -1
- package/dist/devtools-auth-types.js.map +1 -1
- package/dist/devtools-auth-ui.d.ts +1 -1
- package/dist/devtools-auth-ui.d.ts.map +1 -1
- package/dist/devtools-auth-ui.js +13 -5
- package/dist/devtools-auth-ui.js.map +1 -1
- package/dist/devtools-harness.d.ts +1 -0
- package/dist/devtools-harness.d.ts.map +1 -1
- package/dist/devtools-harness.js +12 -7
- package/dist/devtools-harness.js.map +1 -1
- package/dist/devtools-preview.d.ts +1 -0
- package/dist/devtools-preview.d.ts.map +1 -1
- package/dist/devtools-preview.js +21 -6
- package/dist/devtools-preview.js.map +1 -1
- package/dist/devtools-rpc-forwarder.d.ts +1 -0
- package/dist/devtools-rpc-forwarder.d.ts.map +1 -1
- package/dist/devtools-rpc-forwarder.js +2 -1
- package/dist/devtools-rpc-forwarder.js.map +1 -1
- package/dist/preview-session.d.ts +1 -0
- package/dist/preview-session.d.ts.map +1 -1
- package/dist/preview-session.js +1 -0
- package/dist/preview-session.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +3 -3
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-auth-ref.js +5 -2
- package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
- package/node_modules/@noodle-borg/agent-packaging/dist/product-skill-types.d.ts +1 -0
- package/node_modules/@noodle-borg/agent-packaging/dist/product-skill-validation.js +4 -0
- package/node_modules/@noodle-borg/app-package/dist/schema.js +1 -0
- package/node_modules/@noodle-borg/app-package/dist/types.d.ts +1 -0
- package/node_modules/@noodle-borg/authoring/dist/server.d.ts +3 -1
- package/node_modules/@noodle-borg/authoring/dist/server.js +7 -6
- package/node_modules/@noodle-borg/capabilities/dist/index.js +7 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-local-authoring.js +8 -0
- package/node_modules/@noodle-borg/compiler/dist/app-package/compile.js +9 -1
- package/node_modules/@noodle-borg/compiler/dist/artifact/catalog-emission.js +3 -0
- package/node_modules/@noodle-borg/compiler/dist/artifact/types.d.ts +2 -0
- package/node_modules/@noodle-borg/compiler/dist/artifact/version.d.ts +2 -1
- package/node_modules/@noodle-borg/compiler/dist/artifact/version.js +2 -1
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +5 -0
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +12 -2
- package/node_modules/@noodle-borg/module/dist/customer-auth-access.d.ts +7 -0
- package/node_modules/@noodle-borg/module/dist/customer-auth-access.js +6 -0
- package/node_modules/@noodle-borg/module/dist/index.d.ts +1 -0
- package/node_modules/@noodle-borg/module/dist/index.js +1 -0
- package/node_modules/@noodle-borg/protocol/dist/handlers/tools.js +3 -0
- package/node_modules/@noodle-borg/protocol/dist/index.d.ts +1 -0
- package/node_modules/@noodle-borg/protocol/dist/index.js +1 -0
- package/node_modules/@noodle-borg/protocol/dist/mapping.d.ts +5 -1
- package/node_modules/@noodle-borg/protocol/dist/mapping.js +15 -7
- package/node_modules/@noodle-borg/protocol/dist/sdk-server.d.ts +2 -0
- package/node_modules/@noodle-borg/protocol/dist/tool-discovery.d.ts +14 -0
- package/node_modules/@noodle-borg/protocol/dist/tool-discovery.js +12 -0
- package/node_modules/@noodle-borg/protocol/dist/v2/server.js +3 -0
- package/node_modules/@noodle-borg/service/dist/build-info.js +4 -2
- package/node_modules/@noodle-borg/service/dist/customer-auth-audience-binding.js +16 -5
- package/node_modules/@noodle-borg/service/dist/deployment-access-mode.js +24 -0
- package/node_modules/@noodle-borg/service/dist/deployment-activation-precondition.js +27 -0
- package/node_modules/@noodle-borg/service/dist/deployment-authentication.js +19 -0
- package/node_modules/@noodle-borg/service/dist/deployment-execution.js +2 -2
- package/node_modules/@noodle-borg/service/dist/deployment-record-version.js +55 -0
- package/node_modules/@noodle-borg/service/dist/developer-mcp/inspection.js +15 -1
- package/node_modules/@noodle-borg/service/dist/registry-access.js +47 -30
- package/node_modules/@noodle-borg/service/dist/registry-compile.js +42 -1
- package/node_modules/@noodle-borg/service/dist/registry-deploy-transaction.js +105 -15
- package/node_modules/@noodle-borg/service/dist/registry-rollback.js +15 -1
- package/node_modules/@noodle-borg/service/dist/registry-state.d.ts +3 -6
- package/node_modules/@noodle-borg/service/dist/registry-state.js +15 -7
- package/node_modules/@noodle-borg/service/dist/registry-status.js +5 -3
- package/node_modules/@noodle-borg/service/dist/registry-targets.js +43 -28
- package/node_modules/@noodle-borg/service/dist/registry-types.d.ts +4 -2
- package/node_modules/@noodle-borg/service/dist/registry.js +68 -72
- package/node_modules/@noodle-borg/service/dist/routes/access.js +7 -0
- package/node_modules/@noodle-borg/service/dist/routes/auth-doctor-live.js +3 -2
- package/node_modules/@noodle-borg/service/dist/routes/control-plane.js +1 -0
- package/node_modules/@noodle-borg/service/dist/routes/deploy-preflight.js +2 -2
- package/node_modules/@noodle-borg/service/dist/serve-resource-auth.js +1 -1
- package/node_modules/@noodle-borg/service/dist/store/in-memory.d.ts +3 -7
- package/node_modules/@noodle-borg/service/dist/store/in-memory.js +13 -4
- package/node_modules/@noodle-borg/service/dist/store/json-file.d.ts +3 -7
- package/node_modules/@noodle-borg/service/dist/store/json-file.js +15 -6
- package/node_modules/@noodle-borg/service/dist/store/records.js +15 -2
- package/node_modules/@noodle-borg/service/dist/store.d.ts +23 -8
- package/node_modules/@noodle-borg/service/package.json +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/handler.d.ts +2 -3
- package/node_modules/@noodle-borg/transport-http/dist/handler.js +3 -4
- package/node_modules/@noodle-borg/transport-http/dist/identity-authorization.d.ts +3 -2
- package/node_modules/@noodle-borg/transport-http/dist/identity-authorization.js +23 -12
- package/node_modules/@noodle-borg/transport-http/dist/index.d.ts +1 -0
- package/node_modules/@noodle-borg/transport-http/dist/serve-request.js +3 -0
- package/node_modules/@noodle-borg/transport-http/dist/target-authentication.d.ts +15 -0
- package/node_modules/@noodle-borg/transport-http/dist/target-authentication.js +9 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/control-plane.d.ts +23 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/control-plane.js +34 -4
- package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +6 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/index.js +4 -1
- package/node_modules/@noodle-borg/wire-contracts/dist/service-info.d.ts +41 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/service-info.js +26 -0
- package/package.json +2 -2
- package/node_modules/@noodle-borg/service/dist/routes/access-mode.js +0 -7
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { assertUniqueActiveCustomerAuthAudienceBindings, CustomerAuthAudienceConflictError, } from './customer-auth-audience-binding.js';
|
|
1
|
+
import { assertUniqueActiveCustomerAuthAudienceBindings, CustomerAuthAudienceConflictError, hasExactCustomerAuthProjection, } from './customer-auth-audience-binding.js';
|
|
2
|
+
import { deploymentRecordVersionError } from './deployment-record-version.js';
|
|
2
3
|
import { deploymentOwnerSubject } from './registry-helpers.js';
|
|
3
4
|
import { activeRecord, activeRecordVersion } from './registry-state.js';
|
|
4
5
|
import { tenantDeploymentKey, tryServedTargetFor } from './registry-targets.js';
|
|
6
|
+
import { resolveActiveAccessUpdate } from './store/records.js';
|
|
5
7
|
/** Registry-facing access transition with customer audience ownership preflight and atomic translation. */
|
|
6
8
|
export async function updateRegistryAccess(state, tenant, options, loadServed, customerVerifierFactory, hasCustomerAuthConflict) {
|
|
7
|
-
if (options.accessMode === 'customers') {
|
|
9
|
+
if (options.accessMode === 'customers' || options.accessMode === 'mixed') {
|
|
8
10
|
const record = options.serverVersion === undefined
|
|
9
11
|
? await activeRecord(state, tenant)
|
|
10
12
|
: await activeRecordVersion(state, tenant, options.serverVersion);
|
|
@@ -12,7 +14,11 @@ export async function updateRegistryAccess(state, tenant, options, loadServed, c
|
|
|
12
14
|
const auth = served?.served.artifact.server.auth;
|
|
13
15
|
if (record !== undefined &&
|
|
14
16
|
auth !== undefined &&
|
|
15
|
-
(await hasCustomerAuthConflict({
|
|
17
|
+
(await hasCustomerAuthConflict({
|
|
18
|
+
...record,
|
|
19
|
+
accessMode: options.accessMode,
|
|
20
|
+
...(options.accessMode === 'mixed' ? { schemaVersion: 2 } : {}),
|
|
21
|
+
}, auth))) {
|
|
16
22
|
return customerAuthAudienceConflict();
|
|
17
23
|
}
|
|
18
24
|
}
|
|
@@ -41,17 +47,34 @@ export async function updateActiveAccess(state, tenant, options, loadServed, cus
|
|
|
41
47
|
: await activeRecordVersion(state, tenant, options.serverVersion);
|
|
42
48
|
if (record === undefined)
|
|
43
49
|
return noActiveDeployment();
|
|
50
|
+
const versionError = deploymentRecordVersionError(record);
|
|
51
|
+
if (versionError !== undefined) {
|
|
52
|
+
return {
|
|
53
|
+
ok: false,
|
|
54
|
+
status: 409,
|
|
55
|
+
code: 'unsupported_deployment_record_version',
|
|
56
|
+
message: versionError.message,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
44
59
|
const nextAccessMode = options.accessMode;
|
|
45
60
|
const previousAccessMode = record.accessMode ?? 'owner-only';
|
|
46
61
|
const previousOwnerSubject = deploymentOwnerSubject(record);
|
|
47
62
|
const nextOwnerSubject = options.ownerSubject ?? previousOwnerSubject;
|
|
48
63
|
const accessChanged = previousAccessMode !== nextAccessMode;
|
|
49
64
|
const ownerChanged = previousOwnerSubject !== nextOwnerSubject;
|
|
50
|
-
const served = accessChanged || ownerChanged || nextAccessMode === 'customers'
|
|
65
|
+
const served = accessChanged || ownerChanged || nextAccessMode === 'customers' || nextAccessMode === 'mixed'
|
|
51
66
|
? await loadServed(record.deploymentId)
|
|
52
67
|
: undefined;
|
|
53
68
|
const serverAuth = served?.served.artifact.server.auth;
|
|
54
|
-
|
|
69
|
+
const schemaVersion = record.schemaVersion === 2 || (nextAccessMode === 'mixed' && serverAuth !== undefined) ? 2 : 1;
|
|
70
|
+
const policyChanged = schemaVersion !== record.schemaVersion;
|
|
71
|
+
if ((nextAccessMode === 'customers' && serverAuth === undefined) ||
|
|
72
|
+
!hasExactCustomerAuthProjection({
|
|
73
|
+
...record,
|
|
74
|
+
schemaVersion,
|
|
75
|
+
accessMode: nextAccessMode,
|
|
76
|
+
...(record.serverAuth === undefined && serverAuth !== undefined ? { serverAuth } : {}),
|
|
77
|
+
}, serverAuth)) {
|
|
55
78
|
return {
|
|
56
79
|
ok: false,
|
|
57
80
|
status: 409,
|
|
@@ -59,17 +82,23 @@ export async function updateActiveAccess(state, tenant, options, loadServed, cus
|
|
|
59
82
|
message: 'Customer access requires server authentication.',
|
|
60
83
|
};
|
|
61
84
|
}
|
|
62
|
-
if (!accessChanged && !ownerChanged) {
|
|
85
|
+
if (!accessChanged && !ownerChanged && !policyChanged) {
|
|
63
86
|
const committed = state.store === undefined
|
|
64
87
|
? commitInMemoryAccessUpdate(state, tenant, record, {
|
|
65
88
|
accessMode: nextAccessMode,
|
|
66
89
|
expectedAccessMode: record.accessMode,
|
|
90
|
+
...(schemaVersion === 2 ? { schemaVersion: 2 } : {}),
|
|
91
|
+
expectedSchemaVersion: record.schemaVersion,
|
|
92
|
+
expectedManifest: record.manifest,
|
|
67
93
|
expectedOwnerSubject: previousOwnerSubject,
|
|
68
94
|
...(serverAuth !== undefined ? { serverAuth } : {}),
|
|
69
95
|
})
|
|
70
96
|
: await state.store.updateActiveAccess(tenant, record.deploymentId, {
|
|
71
97
|
accessMode: nextAccessMode,
|
|
72
98
|
expectedAccessMode: record.accessMode,
|
|
99
|
+
...(schemaVersion === 2 ? { schemaVersion: 2 } : {}),
|
|
100
|
+
expectedSchemaVersion: record.schemaVersion,
|
|
101
|
+
expectedManifest: record.manifest,
|
|
73
102
|
expectedOwnerSubject: previousOwnerSubject,
|
|
74
103
|
...(serverAuth !== undefined ? { serverAuth } : {}),
|
|
75
104
|
});
|
|
@@ -80,6 +109,7 @@ export async function updateActiveAccess(state, tenant, options, loadServed, cus
|
|
|
80
109
|
ok: true,
|
|
81
110
|
changed: false,
|
|
82
111
|
accessChanged: false,
|
|
112
|
+
policyChanged: false,
|
|
83
113
|
ownerChanged: false,
|
|
84
114
|
previousAccessMode,
|
|
85
115
|
...(previousOwnerSubject !== undefined ? { previousOwnerSubject } : {}),
|
|
@@ -107,8 +137,9 @@ export async function updateActiveAccess(state, tenant, options, loadServed, cus
|
|
|
107
137
|
const updated = {
|
|
108
138
|
...record,
|
|
109
139
|
accessMode: nextAccessMode,
|
|
140
|
+
schemaVersion,
|
|
110
141
|
...(ownerChanged && nextOwnerSubject !== undefined ? { ownerSubject: nextOwnerSubject } : {}),
|
|
111
|
-
...(
|
|
142
|
+
...(serverAuth !== undefined ? { serverAuth } : {}),
|
|
112
143
|
};
|
|
113
144
|
const target = tryServedTargetFor(updated, served.served, customerVerifierFactory);
|
|
114
145
|
if (target === undefined)
|
|
@@ -120,6 +151,9 @@ export async function updateActiveAccess(state, tenant, options, loadServed, cus
|
|
|
120
151
|
? { ownerSubject: nextOwnerSubject }
|
|
121
152
|
: {}),
|
|
122
153
|
expectedAccessMode: record.accessMode,
|
|
154
|
+
...(schemaVersion === 2 ? { schemaVersion: 2 } : {}),
|
|
155
|
+
expectedSchemaVersion: record.schemaVersion,
|
|
156
|
+
expectedManifest: record.manifest,
|
|
123
157
|
expectedOwnerSubject: previousOwnerSubject,
|
|
124
158
|
...(serverAuth !== undefined ? { serverAuth } : {}),
|
|
125
159
|
})
|
|
@@ -129,6 +163,9 @@ export async function updateActiveAccess(state, tenant, options, loadServed, cus
|
|
|
129
163
|
? { ownerSubject: nextOwnerSubject }
|
|
130
164
|
: {}),
|
|
131
165
|
expectedAccessMode: record.accessMode,
|
|
166
|
+
...(schemaVersion === 2 ? { schemaVersion: 2 } : {}),
|
|
167
|
+
expectedSchemaVersion: record.schemaVersion,
|
|
168
|
+
expectedManifest: record.manifest,
|
|
132
169
|
expectedOwnerSubject: previousOwnerSubject,
|
|
133
170
|
...(serverAuth !== undefined ? { serverAuth } : {}),
|
|
134
171
|
});
|
|
@@ -140,6 +177,7 @@ export async function updateActiveAccess(state, tenant, options, loadServed, cus
|
|
|
140
177
|
ok: true,
|
|
141
178
|
changed: true,
|
|
142
179
|
accessChanged,
|
|
180
|
+
policyChanged,
|
|
143
181
|
ownerChanged,
|
|
144
182
|
previousAccessMode,
|
|
145
183
|
...(previousOwnerSubject !== undefined ? { previousOwnerSubject } : {}),
|
|
@@ -147,30 +185,9 @@ export async function updateActiveAccess(state, tenant, options, loadServed, cus
|
|
|
147
185
|
};
|
|
148
186
|
}
|
|
149
187
|
function commitInMemoryAccessUpdate(state, tenant, observed, input) {
|
|
150
|
-
const
|
|
151
|
-
if (
|
|
152
|
-
!current.active ||
|
|
153
|
-
current.archivedAt !== undefined ||
|
|
154
|
-
current.orgSlug !== tenant.org ||
|
|
155
|
-
current.appSlug !== tenant.app ||
|
|
156
|
-
current.environment !== tenant.env ||
|
|
157
|
-
current.accessMode !== input.expectedAccessMode ||
|
|
158
|
-
deploymentOwnerSubject(current) !== input.expectedOwnerSubject) {
|
|
188
|
+
const committed = resolveActiveAccessUpdate(state.records.get(observed.deploymentId), tenant, input);
|
|
189
|
+
if (committed === undefined)
|
|
159
190
|
return undefined;
|
|
160
|
-
}
|
|
161
|
-
if ((current.accessMode ?? 'owner-only') === input.accessMode &&
|
|
162
|
-
(input.ownerSubject === undefined || deploymentOwnerSubject(current) === input.ownerSubject) &&
|
|
163
|
-
input.accessMode !== 'customers') {
|
|
164
|
-
return current;
|
|
165
|
-
}
|
|
166
|
-
const committed = {
|
|
167
|
-
...current,
|
|
168
|
-
accessMode: input.accessMode,
|
|
169
|
-
...(input.ownerSubject !== undefined ? { ownerSubject: input.ownerSubject } : {}),
|
|
170
|
-
...(input.accessMode === 'customers' && input.serverAuth !== undefined
|
|
171
|
-
? { serverAuth: input.serverAuth }
|
|
172
|
-
: {}),
|
|
173
|
-
};
|
|
174
191
|
const proposed = new Map(state.records).set(committed.deploymentId, committed);
|
|
175
192
|
assertUniqueActiveCustomerAuthAudienceBindings([...proposed.values()]);
|
|
176
193
|
state.records.set(committed.deploymentId, committed);
|
|
@@ -4,12 +4,24 @@ import { compileConnectors, delegatedTokenExchangeIdentityErrors, } from '@noodl
|
|
|
4
4
|
import { InMemoryConnectorRegistry, resolveManagedOrigins, resolveVariableEnvironment, } from '@noodle-borg/runtime';
|
|
5
5
|
import { AppPackageSnapshotError, createAppPackageSnapshot, } from './app-package-snapshot.js';
|
|
6
6
|
import { missingServerConfigErrors } from './assistant-bindings.js';
|
|
7
|
+
import { normalizePersistedConnectorsForCompile } from './connector-normalize.js';
|
|
7
8
|
import { ManagedConfigBroker } from './credential-broker.js';
|
|
8
9
|
import { deploymentCredentialBrokerOptions } from './credential-broker-options.js';
|
|
10
|
+
import { deploymentRecordVersionError } from './deployment-record-version.js';
|
|
9
11
|
import { normalizePersistedManifestForCompile } from './manifest-normalize.js';
|
|
10
|
-
import { missingSecretErrors, missingVariableErrors } from './registry-helpers.js';
|
|
12
|
+
import { missingCapabilityErrors, missingSecretErrors, missingVariableErrors, } from './registry-helpers.js';
|
|
13
|
+
import { servedTargetFor } from './registry-targets.js';
|
|
11
14
|
import { createDeploymentStateConnector, } from './state-connector-factory.js';
|
|
12
15
|
import { resolveConfigScope, } from './store.js';
|
|
16
|
+
/** Reject unsupported persisted semantics before constructing executable runtime dependencies. */
|
|
17
|
+
export async function compilePersistedRegistryRecord(record, compileTarget) {
|
|
18
|
+
const versionError = deploymentRecordVersionError(record);
|
|
19
|
+
if (versionError !== undefined)
|
|
20
|
+
return { ok: false, errors: [versionError] };
|
|
21
|
+
return compileTarget({ org: record.orgSlug, app: record.appSlug, env: record.environment }, record.manifest, record.connectors === undefined
|
|
22
|
+
? undefined
|
|
23
|
+
: normalizePersistedConnectorsForCompile(record.connectors), record.hostedAssets, false, record.deploymentId);
|
|
24
|
+
}
|
|
13
25
|
export async function compileRegistryTarget(context, input) {
|
|
14
26
|
const { tenant, manifest, connectors, hostedAssets, deploymentId } = input;
|
|
15
27
|
let catalogConnectors = [];
|
|
@@ -216,4 +228,33 @@ export async function compileRegistryTarget(context, input) {
|
|
|
216
228
|
...(appPackageSnapshot !== undefined ? { appPackageSnapshot } : {}),
|
|
217
229
|
};
|
|
218
230
|
}
|
|
231
|
+
/** Load and validate persisted semantics before publishing an executable target to caches. */
|
|
232
|
+
export async function loadPersistedRegistryTarget(source, context) {
|
|
233
|
+
const { state } = context;
|
|
234
|
+
const record = typeof source === 'string'
|
|
235
|
+
? state.store
|
|
236
|
+
? await state.store.get(source)
|
|
237
|
+
: state.records.get(source)
|
|
238
|
+
: source;
|
|
239
|
+
if (!record ||
|
|
240
|
+
record.archivedAt !== undefined ||
|
|
241
|
+
deploymentRecordVersionError(record) !== undefined)
|
|
242
|
+
return undefined;
|
|
243
|
+
const deploymentId = record.deploymentId;
|
|
244
|
+
const built = await context.compile(record);
|
|
245
|
+
if (!built.ok) {
|
|
246
|
+
throw new Error(`deployment ${deploymentId} failed to recompile (${built.errors.map((e) => e.code).join(',')})`);
|
|
247
|
+
}
|
|
248
|
+
const missingCapabilities = missingCapabilityErrors(built.served.artifact.requirements?.capabilities ?? [], context.capabilities);
|
|
249
|
+
if (missingCapabilities.length > 0) {
|
|
250
|
+
throw new Error(`deployment ${deploymentId} failed capability requirements (${missingCapabilities.map((e) => e.path).join(',')})`);
|
|
251
|
+
}
|
|
252
|
+
if (record.active &&
|
|
253
|
+
(await context.hasCustomerAuthConflict(record, built.served.artifact.server.auth)))
|
|
254
|
+
return undefined;
|
|
255
|
+
const target = servedTargetFor(record, built.served, context.customerVerifierFactory);
|
|
256
|
+
state.servers.set(deploymentId, target);
|
|
257
|
+
state.records.set(deploymentId, record);
|
|
258
|
+
return target;
|
|
259
|
+
}
|
|
219
260
|
//# sourceMappingURL=registry-compile.js.map
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { normalizeServerVersion } from '@noodle-borg/module';
|
|
2
|
+
import { deploymentAuthenticationFor } from './deployment-authentication.js';
|
|
3
|
+
import { deploymentRecordVersionError } from './deployment-record-version.js';
|
|
4
|
+
import { sameTenantRecord } from './deployment-versioning.js';
|
|
2
5
|
import { deployAccessRequiresActor, deployerRequiredError, deploymentOwnerSubject, emptyMembershipSourcesError, membershipSourcesRequireOrgMembersError, missingCapabilityErrors, serverAuthRequiredError, } from './registry-helpers.js';
|
|
3
|
-
import {
|
|
6
|
+
import { activeRecordVersion } from './registry-state.js';
|
|
7
|
+
import { emptySecretEnvelope, idempotentDeploymentId, mintDeploymentId, } from './registry-targets.js';
|
|
4
8
|
/** Serialize candidate validation/activation with hierarchical configuration writers. */
|
|
5
9
|
export async function withDeploymentConfiguration(config, org, work) {
|
|
6
10
|
if (!config.transactConfig)
|
|
@@ -19,6 +23,11 @@ export async function withDeploymentConfiguration(config, org, work) {
|
|
|
19
23
|
throw error;
|
|
20
24
|
}
|
|
21
25
|
}
|
|
26
|
+
/** Validate the exact destination scope before compilation or publication side effects. */
|
|
27
|
+
export async function deploymentWriteVersionError(state, tenant, serverVersion) {
|
|
28
|
+
const active = await activeDeploymentWriteScope(state, tenant, serverVersion);
|
|
29
|
+
return active === undefined ? undefined : deploymentRecordVersionError(active);
|
|
30
|
+
}
|
|
22
31
|
export async function preflightRegistryDeploy(input) {
|
|
23
32
|
const { actor, accessMode, orgMembershipSources } = input.options;
|
|
24
33
|
if (input.options.serverVersion !== undefined) {
|
|
@@ -32,6 +41,9 @@ export async function preflightRegistryDeploy(input) {
|
|
|
32
41
|
const artifact = built.ok ? built.served.artifact : built.compiledArtifact;
|
|
33
42
|
if (artifact !== undefined) {
|
|
34
43
|
errors.push(...missingCapabilityErrors(artifact.requirements?.capabilities ?? [], input.serviceCapabilities));
|
|
44
|
+
if (accessMode === 'mixed' && artifact.server.auth !== undefined && actor === undefined) {
|
|
45
|
+
errors.push(...deployerRequiredError(accessMode).errors);
|
|
46
|
+
}
|
|
35
47
|
if (accessMode === 'customers' && artifact.server.auth === undefined) {
|
|
36
48
|
errors.push(...serverAuthRequiredError().errors);
|
|
37
49
|
}
|
|
@@ -67,6 +79,10 @@ export async function resolveDeployAttempt(input) {
|
|
|
67
79
|
const existing = (await input.store?.get(deploymentId)) ?? input.records.get(deploymentId);
|
|
68
80
|
if (existing === undefined)
|
|
69
81
|
return { deploymentId };
|
|
82
|
+
const versionError = deploymentRecordVersionError(existing);
|
|
83
|
+
if (versionError !== undefined) {
|
|
84
|
+
return { deploymentId, replay: { ok: false, errors: [versionError] } };
|
|
85
|
+
}
|
|
70
86
|
if (!sameIdempotentDeploy(existing, input.tenant, input.manifest, input.options)) {
|
|
71
87
|
return {
|
|
72
88
|
deploymentId,
|
|
@@ -78,18 +94,23 @@ export async function resolveDeployAttempt(input) {
|
|
|
78
94
|
},
|
|
79
95
|
};
|
|
80
96
|
}
|
|
81
|
-
const ownerSubject = deploymentOwnerSubject(existing);
|
|
82
97
|
return {
|
|
83
98
|
deploymentId,
|
|
84
|
-
replay: {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
99
|
+
replay: { ...deployedRecordResult(existing), replayed: true },
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** Deploy and retry responses report the committed operator policy, never the requested intent. */
|
|
103
|
+
export function deployedRecordResult(record) {
|
|
104
|
+
const ownerSubject = deploymentOwnerSubject(record);
|
|
105
|
+
const authentication = deploymentAuthenticationFor(record);
|
|
106
|
+
return {
|
|
107
|
+
ok: true,
|
|
108
|
+
deploymentId: record.deploymentId,
|
|
109
|
+
deploymentVersion: record.deploymentVersion,
|
|
110
|
+
...(record.serverVersion !== undefined ? { serverVersion: record.serverVersion } : {}),
|
|
111
|
+
...(record.accessMode !== undefined ? { accessMode: record.accessMode } : {}),
|
|
112
|
+
...(authentication !== undefined ? { authentication } : {}),
|
|
113
|
+
...(ownerSubject !== undefined ? { ownerSubject } : {}),
|
|
93
114
|
};
|
|
94
115
|
}
|
|
95
116
|
function sameIdempotentDeploy(record, tenant, manifest, options) {
|
|
@@ -102,14 +123,83 @@ function sameIdempotentDeploy(record, tenant, manifest, options) {
|
|
|
102
123
|
record.serverVersion === serverVersion &&
|
|
103
124
|
record.manifest === manifest &&
|
|
104
125
|
record.connectors === options.connectors &&
|
|
105
|
-
record.
|
|
126
|
+
(record.schemaVersion === 2 ||
|
|
127
|
+
(record.accessMode === options.accessMode &&
|
|
128
|
+
(options.accessMode !== 'owner-only' ||
|
|
129
|
+
deploymentOwnerSubject(record) === (options.ownerSubject ?? options.actor?.subject)))) &&
|
|
106
130
|
record.deploymentSource === options.deploymentSource &&
|
|
107
131
|
sameJson(record.hostedAssets, options.hostedAssets) &&
|
|
108
|
-
sameJson(record.orgMembershipSources, options.orgMembershipSources)
|
|
109
|
-
(options.accessMode !== 'owner-only' ||
|
|
110
|
-
deploymentOwnerSubject(record) === (options.ownerSubject ?? options.actor?.subject)));
|
|
132
|
+
sameJson(record.orgMembershipSources, options.orgMembershipSources));
|
|
111
133
|
}
|
|
112
134
|
function sameJson(left, right) {
|
|
113
135
|
return JSON.stringify(left) === JSON.stringify(right);
|
|
114
136
|
}
|
|
137
|
+
/** Writes target one exact scope; default routing deliberately prefers a versioned deployment. */
|
|
138
|
+
async function activeDeploymentWriteScope(state, tenant, serverVersion) {
|
|
139
|
+
if (serverVersion !== undefined)
|
|
140
|
+
return activeRecordVersion(state, tenant, serverVersion);
|
|
141
|
+
// The existing store port has no unversioned point lookup. Read durable records, never a worker cache.
|
|
142
|
+
const records = state.store ? await state.store.loadAll() : [...state.records.values()];
|
|
143
|
+
return records
|
|
144
|
+
.filter((record) => record.active &&
|
|
145
|
+
record.archivedAt === undefined &&
|
|
146
|
+
record.serverVersion === undefined &&
|
|
147
|
+
sameTenantRecord(record, tenant))
|
|
148
|
+
.sort((a, b) => b.deploymentVersion - a.deploymentVersion)[0];
|
|
149
|
+
}
|
|
150
|
+
/** Existing dormant mixed declarations require an explicit operator adoption. */
|
|
151
|
+
function mixedCustomerActivationError(previous, previousAuth, accessMode, auth) {
|
|
152
|
+
return previous?.schemaVersion === 1 &&
|
|
153
|
+
previous.accessMode === 'mixed' &&
|
|
154
|
+
previousAuth !== undefined &&
|
|
155
|
+
accessMode === 'mixed' &&
|
|
156
|
+
auth !== undefined
|
|
157
|
+
? {
|
|
158
|
+
code: 'customer_auth_activation_required',
|
|
159
|
+
path: 'accessMode',
|
|
160
|
+
message: 'Activate customer authentication with noodle access set mixed before redeploying this existing mixed deployment.',
|
|
161
|
+
}
|
|
162
|
+
: undefined;
|
|
163
|
+
}
|
|
164
|
+
/** Bind replacement policy to the observed active revision before the atomic store write. */
|
|
165
|
+
export async function replacementDeploymentPolicy(state, tenant, serverVersion, accessMode, auth, compile) {
|
|
166
|
+
const previous = await activeDeploymentWriteScope(state, tenant, serverVersion);
|
|
167
|
+
const previousBuilt = previous === undefined ? undefined : await compile(previous);
|
|
168
|
+
return {
|
|
169
|
+
previous,
|
|
170
|
+
schemaVersion: previous?.schemaVersion === 2 || (accessMode === 'mixed' && auth !== undefined) ? 2 : 1,
|
|
171
|
+
error: mixedCustomerActivationError(previous, previousBuilt?.ok ? previousBuilt.served.artifact.server.auth : previous?.serverAuth, accessMode, auth),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/** Construct one immutable deployment candidate from compiled source and resolved operator policy. */
|
|
175
|
+
export function createRegistryDeployRecord(input) {
|
|
176
|
+
const { safeTenant, safeServerVersion, deploymentId, version, built, manifest, options, schemaVersion, appPackageSnapshot, } = input;
|
|
177
|
+
const { actor, accessMode, automationId, deploymentSource, orgMembershipSources, connectors, hostedAssets, } = options;
|
|
178
|
+
const serverAuth = built.artifact.server.auth;
|
|
179
|
+
const ownerSubject = accessMode === 'owner-only' ? (options.ownerSubject ?? actor?.subject) : undefined;
|
|
180
|
+
const record = {
|
|
181
|
+
schemaVersion,
|
|
182
|
+
deploymentId,
|
|
183
|
+
orgSlug: safeTenant.org,
|
|
184
|
+
appSlug: safeTenant.app,
|
|
185
|
+
environment: safeTenant.env,
|
|
186
|
+
...(safeServerVersion !== undefined ? { serverVersion: safeServerVersion } : {}),
|
|
187
|
+
deploymentVersion: version,
|
|
188
|
+
active: automationId === undefined,
|
|
189
|
+
serverName: built.artifact.server.name,
|
|
190
|
+
createdAt: new Date().toISOString(),
|
|
191
|
+
...(actor ? { createdBySubject: actor.subject, createdByEmail: actor.email } : {}),
|
|
192
|
+
...(ownerSubject !== undefined ? { ownerSubject } : {}),
|
|
193
|
+
...(deploymentSource !== undefined ? { deploymentSource } : {}),
|
|
194
|
+
...(accessMode !== undefined ? { accessMode } : {}),
|
|
195
|
+
...(orgMembershipSources !== undefined ? { orgMembershipSources } : {}),
|
|
196
|
+
...(serverAuth !== undefined ? { serverAuth } : {}),
|
|
197
|
+
manifest,
|
|
198
|
+
...(connectors !== undefined ? { connectors } : {}),
|
|
199
|
+
...(hostedAssets !== undefined && hostedAssets.length > 0 ? { hostedAssets } : {}),
|
|
200
|
+
...(appPackageSnapshot !== undefined ? { appPackageSnapshot } : {}),
|
|
201
|
+
secrets: emptySecretEnvelope(),
|
|
202
|
+
};
|
|
203
|
+
return record;
|
|
204
|
+
}
|
|
115
205
|
//# sourceMappingURL=registry-deploy-transaction.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { hasExactCustomerAuthProjection } from './customer-auth-audience-binding.js';
|
|
1
2
|
import { withDeploymentConfiguration } from './registry-deploy-transaction.js';
|
|
2
3
|
import { deploymentOwnerSubject, missingCapabilityErrors } from './registry-helpers.js';
|
|
3
4
|
import { activateInMemory } from './registry-state.js';
|
|
@@ -52,9 +53,18 @@ export async function rollbackDeployment(state, ref, deploymentId, compilePersis
|
|
|
52
53
|
};
|
|
53
54
|
}
|
|
54
55
|
const compiledAuth = built.served.artifact.server.auth;
|
|
56
|
+
if (target.serverAuth !== undefined && !hasExactCustomerAuthProjection(target, compiledAuth)) {
|
|
57
|
+
return {
|
|
58
|
+
ok: false,
|
|
59
|
+
status: 409,
|
|
60
|
+
error: 'deployment cannot be activated: server_auth_required',
|
|
61
|
+
};
|
|
62
|
+
}
|
|
55
63
|
const projectedTarget = {
|
|
56
64
|
...target,
|
|
57
|
-
...(target.accessMode === 'customers'
|
|
65
|
+
...((target.accessMode === 'customers' ||
|
|
66
|
+
(target.schemaVersion === 2 && target.accessMode === 'mixed')) &&
|
|
67
|
+
compiledAuth !== undefined
|
|
58
68
|
? { serverAuth: compiledAuth }
|
|
59
69
|
: {}),
|
|
60
70
|
};
|
|
@@ -75,10 +85,14 @@ export async function rollbackDeployment(state, ref, deploymentId, compilePersis
|
|
|
75
85
|
const activation = state.store
|
|
76
86
|
? await state.store.activateDeployment(ref, deploymentId, {
|
|
77
87
|
expectedAccessMode: target.accessMode,
|
|
88
|
+
expectedSchemaVersion: target.schemaVersion,
|
|
89
|
+
expectedRevision: target,
|
|
78
90
|
...(compiledAuth !== undefined ? { serverAuth: compiledAuth } : {}),
|
|
79
91
|
})
|
|
80
92
|
: activateInMemory(state.records, ref, deploymentId, {
|
|
81
93
|
expectedAccessMode: target.accessMode,
|
|
94
|
+
expectedSchemaVersion: target.schemaVersion,
|
|
95
|
+
expectedRevision: target,
|
|
82
96
|
...(compiledAuth !== undefined ? { serverAuth: compiledAuth } : {}),
|
|
83
97
|
});
|
|
84
98
|
if (activation === undefined) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ServedTarget } from '@noodle-borg/transport-http';
|
|
2
|
-
import type { AppArchiveResult, AppRestoreResult, AppSummary, ArtifactStore, CustomerAuthRestoreProjection, DeploymentLock, DeploymentLockUpdateResult, DeploymentSummary, DeployRecord, EnvSummary, ProductionEnvironmentChange, TenantAuthConfig, TenantRef } from './store.js';
|
|
2
|
+
import type { AppArchiveResult, AppRestoreResult, AppSummary, ArtifactStore, CustomerAuthRestoreProjection, DeploymentActivationPrecondition, DeploymentLock, DeploymentLockUpdateResult, DeploymentPolicyPrecondition, DeploymentSummary, DeployRecord, EnvSummary, ProductionEnvironmentChange, TenantAuthConfig, TenantRef } from './store.js';
|
|
3
3
|
export interface RegistryStateView {
|
|
4
4
|
readonly store: ArtifactStore | undefined;
|
|
5
5
|
readonly records: Map<string, DeployRecord>;
|
|
@@ -32,12 +32,9 @@ export declare function reconcilePlatformAccountResetRegistryCache(state: Regist
|
|
|
32
32
|
* store owns deactivation; without one the caches are reconciled in-process so no instance serves a stale
|
|
33
33
|
* active record.
|
|
34
34
|
*/
|
|
35
|
-
export declare function persistDeployRecord(view: RegistryStateView, record: DeployRecord, tenant: TenantRef, activatesNow: boolean): Promise<DeployRecord>;
|
|
35
|
+
export declare function persistDeployRecord(view: RegistryStateView, record: DeployRecord, tenant: TenantRef, activatesNow: boolean, precondition?: DeploymentPolicyPrecondition): Promise<DeployRecord>;
|
|
36
36
|
/** No-store activation fallback (moved verbatim from `ServerRegistry.#activateInMemory`). */
|
|
37
|
-
export declare function activateInMemory(records: Map<string, DeployRecord>, ref: TenantRef, deploymentId: string, precondition?: {
|
|
38
|
-
readonly expectedAccessMode: DeployRecord['accessMode'];
|
|
39
|
-
readonly serverAuth?: DeployRecord['serverAuth'];
|
|
40
|
-
}): {
|
|
37
|
+
export declare function activateInMemory(records: Map<string, DeployRecord>, ref: TenantRef, deploymentId: string, precondition?: DeploymentActivationPrecondition): {
|
|
41
38
|
readonly active: DeployRecord;
|
|
42
39
|
readonly previousActive?: DeployRecord;
|
|
43
40
|
readonly alreadyActive: boolean;
|
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
* durable store first, then reconcile the in-process caches so no instance keeps serving stale state.
|
|
6
6
|
*/
|
|
7
7
|
import { normalizeServerVersion } from '@noodle-borg/module';
|
|
8
|
-
import { assertCustomerAuthRestorePrecondition, assertUniqueActiveCustomerAuthAudienceBindings, CustomerAuthAudienceProjectionError, hasExactCustomerAuthProjection, } from './customer-auth-audience-binding.js';
|
|
8
|
+
import { assertCustomerAuthRestorePrecondition, assertUniqueActiveCustomerAuthAudienceBindings, CustomerAuthAudienceProjectionError, hasExactCustomerAuthProjection, requiresCustomerAuthProjection, } from './customer-auth-audience-binding.js';
|
|
9
|
+
import { matchesDeploymentActivation } from './deployment-activation-precondition.js';
|
|
9
10
|
import { assertDeploymentActivationUnlocked, assertDeploymentAppendUnlocked, } from './deployment-lock.js';
|
|
11
|
+
import { assertDeploymentAppendPolicy, assertDeploymentAppendVersion, } from './deployment-record-version.js';
|
|
10
12
|
import { defaultActiveRecord } from './deployment-versioning.js';
|
|
11
13
|
import { recordMatchesTenant, tenantDeploymentKey, tenantKey } from './registry-targets.js';
|
|
12
14
|
import { appArchivedAt, deploymentSummary, paginateAppSummaries, planAppArchive, planAppRestore, planArchivedAppSweep, resolveProductionEnvironment, summarizeApps, summarizeEnvs, withoutArchiveStamp, } from './store/records.js';
|
|
@@ -26,14 +28,16 @@ export function reconcilePlatformAccountResetRegistryCache(state, input) {
|
|
|
26
28
|
* store owns deactivation; without one the caches are reconciled in-process so no instance serves a stale
|
|
27
29
|
* active record.
|
|
28
30
|
*/
|
|
29
|
-
export async function persistDeployRecord(view, record, tenant, activatesNow) {
|
|
31
|
+
export async function persistDeployRecord(view, record, tenant, activatesNow, precondition) {
|
|
30
32
|
if (view.store) {
|
|
31
|
-
await view.store.append(record);
|
|
33
|
+
await view.store.append(record, precondition);
|
|
32
34
|
const persisted = (await view.store.get(record.deploymentId)) ?? record;
|
|
33
35
|
view.records.set(record.deploymentId, persisted);
|
|
34
36
|
return persisted;
|
|
35
37
|
}
|
|
36
38
|
else {
|
|
39
|
+
assertDeploymentAppendVersion([...view.records.values()], record);
|
|
40
|
+
assertDeploymentAppendPolicy([...view.records.values()], record, precondition);
|
|
37
41
|
if (!assertDeploymentAppendUnlocked([...view.records.values()], record)) {
|
|
38
42
|
return view.records.get(record.deploymentId);
|
|
39
43
|
}
|
|
@@ -66,18 +70,22 @@ export function activateInMemory(records, ref, deploymentId, precondition) {
|
|
|
66
70
|
if (target === undefined || !recordMatchesTenant(target, ref))
|
|
67
71
|
return undefined;
|
|
68
72
|
assertDeploymentActivationUnlocked([...records.values()], target);
|
|
69
|
-
if (
|
|
73
|
+
if (!matchesDeploymentActivation(target, precondition)) {
|
|
70
74
|
return undefined;
|
|
71
75
|
}
|
|
72
76
|
const previousActive = [...records.values()]
|
|
73
77
|
.filter((record) => record.active && recordMatchesTenant(record, ref))
|
|
74
78
|
.filter((record) => record.serverVersion === target.serverVersion)
|
|
75
79
|
.sort((a, b) => b.deploymentVersion - a.deploymentVersion)[0];
|
|
80
|
+
if (precondition === undefined && previousActive !== undefined) {
|
|
81
|
+
assertDeploymentAppendVersion([previousActive], { ...target, active: true });
|
|
82
|
+
}
|
|
76
83
|
const alreadyActive = previousActive?.deploymentId === deploymentId;
|
|
77
84
|
const activated = {
|
|
78
85
|
...target,
|
|
79
86
|
active: true,
|
|
80
|
-
...(target
|
|
87
|
+
...(requiresCustomerAuthProjection(target, precondition?.serverAuth) &&
|
|
88
|
+
precondition?.serverAuth !== undefined
|
|
81
89
|
? { serverAuth: precondition.serverAuth }
|
|
82
90
|
: {}),
|
|
83
91
|
};
|
|
@@ -207,7 +215,7 @@ export async function registryRestoreApp(state, org, app, compileRecord) {
|
|
|
207
215
|
return undefined;
|
|
208
216
|
const projections = [];
|
|
209
217
|
for (const record of plan.clear) {
|
|
210
|
-
if (!record.active || record
|
|
218
|
+
if (!record.active || !requiresCustomerAuthProjection(record))
|
|
211
219
|
continue;
|
|
212
220
|
const built = await compileRecord(record);
|
|
213
221
|
const compiledAuth = built.ok ? built.served.artifact.server.auth : undefined;
|
|
@@ -243,7 +251,7 @@ export async function registryCustomerAuthRestoreProjections(state, deploymentId
|
|
|
243
251
|
: state.store.get(deploymentId)));
|
|
244
252
|
const projections = [];
|
|
245
253
|
for (const record of records) {
|
|
246
|
-
if (record === undefined || !record.active || record
|
|
254
|
+
if (record === undefined || !record.active || !requiresCustomerAuthProjection(record))
|
|
247
255
|
continue;
|
|
248
256
|
const built = await compileRecord(record);
|
|
249
257
|
const compiledAuth = built.ok ? built.served.artifact.server.auth : undefined;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { tenantMcpUrl } from '@noodle-borg/module';
|
|
2
|
+
import { hasExactCustomerAuthProjection } from './customer-auth-audience-binding.js';
|
|
3
|
+
import { deploymentAuthenticationFor } from './deployment-authentication.js';
|
|
2
4
|
import { deploymentOwnerSubject, missingSecretNames } from './registry-helpers.js';
|
|
3
5
|
/** Project one compiled deployment into the control-plane status contract. */
|
|
4
6
|
export function deploymentStatusFor(ref, record, built, baseUrl, endpointOptions) {
|
|
5
7
|
const missingSecrets = built.ok ? [] : missingSecretNames(built.errors);
|
|
6
|
-
const missingCustomerAuth = built.ok &&
|
|
7
|
-
record.accessMode === 'customers' &&
|
|
8
|
-
built.served.artifact.server.auth === undefined;
|
|
8
|
+
const missingCustomerAuth = built.ok && !hasExactCustomerAuthProjection(record, built.served.artifact.server.auth);
|
|
9
9
|
const unhealthy = missingCustomerAuth || (!built.ok && missingSecrets.length === 0);
|
|
10
10
|
const ownerSubject = deploymentOwnerSubject(record);
|
|
11
|
+
const authentication = deploymentAuthenticationFor(record, built.ok ? built.served.artifact.server.auth : undefined);
|
|
11
12
|
return {
|
|
12
13
|
target: ref,
|
|
13
14
|
deployment: {
|
|
@@ -20,6 +21,7 @@ export function deploymentStatusFor(ref, record, built, baseUrl, endpointOptions
|
|
|
20
21
|
...(record.createdByEmail !== undefined ? { createdByEmail: record.createdByEmail } : {}),
|
|
21
22
|
...(ownerSubject !== undefined ? { ownerSubject } : {}),
|
|
22
23
|
accessMode: record.accessMode ?? 'owner-only',
|
|
24
|
+
...(authentication !== undefined ? { authentication } : {}),
|
|
23
25
|
...(record.deploymentLock !== undefined
|
|
24
26
|
? {
|
|
25
27
|
deploymentLock: {
|