@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
|
@@ -3,8 +3,10 @@ import { mkdir, readdir, readFile, rename, rm, writeFile } from 'node:fs/promise
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { normalizeServerVersion } from '@noodle-borg/module';
|
|
5
5
|
import { assertSameAppPackageSnapshot, sanitizeDeployRecordAppPackageSnapshot, } from '../app-package-snapshot.js';
|
|
6
|
-
import { assertCustomerAuthRestorePrecondition, assertUniqueActiveCustomerAuthAudienceBindings, findActiveCustomerAuthAudienceConflict, } from '../customer-auth-audience-binding.js';
|
|
6
|
+
import { assertCustomerAuthRestorePrecondition, assertUniqueActiveCustomerAuthAudienceBindings, findActiveCustomerAuthAudienceConflict, requiresCustomerAuthProjection, } from '../customer-auth-audience-binding.js';
|
|
7
|
+
import { matchesDeploymentActivation } from '../deployment-activation-precondition.js';
|
|
7
8
|
import { assertDeploymentActivationUnlocked, assertDeploymentAppendUnlocked, } from '../deployment-lock.js';
|
|
9
|
+
import { assertDeploymentAppendPolicy, assertDeploymentAppendVersion, } from '../deployment-record-version.js';
|
|
8
10
|
import { defaultActiveRecord, sameDeploymentScope, sameTenantRecord, } from '../deployment-versioning.js';
|
|
9
11
|
import { appArchivedAt, deploymentSummary, matchesDeploymentFilter, paginateAppSummaries, planAppArchive, planAppRestore, planArchivedAppSweep, preserveDeploymentOwnerState, resolveActiveAccessUpdate, resolveProductionEnvironment, summarizeApps, summarizeEnvs, validateDeploymentListFilter, withoutArchiveStamp, } from './records.js';
|
|
10
12
|
import { DEPLOYMENT_ID_PATTERN, validateSlug, validateTenantRef } from './validate.js';
|
|
@@ -22,10 +24,10 @@ export class JsonFileArtifactStore {
|
|
|
22
24
|
this.#dir = join(dataDir, 'deployments');
|
|
23
25
|
this.#environmentMetadataDir = join(dataDir, 'environment-metadata');
|
|
24
26
|
}
|
|
25
|
-
append(record) {
|
|
26
|
-
return this.#serializeLifecycle(() => this.#appendUnlocked(record));
|
|
27
|
+
append(record, precondition) {
|
|
28
|
+
return this.#serializeLifecycle(() => this.#appendUnlocked(record, precondition));
|
|
27
29
|
}
|
|
28
|
-
async #appendUnlocked(record) {
|
|
30
|
+
async #appendUnlocked(record, precondition) {
|
|
29
31
|
// Defence in depth: `deploymentId` becomes a filename, so reject anything outside the minted shape
|
|
30
32
|
// (`mintDeploymentId` only ever produces `[a-z0-9-]`). Guards this public class against a caller that
|
|
31
33
|
// passes an untrusted id (no path traversal, no escaping the data dir).
|
|
@@ -34,6 +36,8 @@ export class JsonFileArtifactStore {
|
|
|
34
36
|
throw new Error(`invalid deploymentId for persistence: "${record.deploymentId}"`);
|
|
35
37
|
}
|
|
36
38
|
const records = await this.loadAll();
|
|
39
|
+
assertDeploymentAppendVersion(records, record);
|
|
40
|
+
assertDeploymentAppendPolicy(records, record, precondition);
|
|
37
41
|
const existing = records.find((candidate) => candidate.deploymentId === record.deploymentId);
|
|
38
42
|
if (existing !== undefined)
|
|
39
43
|
assertSameAppPackageSnapshot(existing, record);
|
|
@@ -127,7 +131,7 @@ export class JsonFileArtifactStore {
|
|
|
127
131
|
const target = await this.get(deploymentId);
|
|
128
132
|
if (target === undefined || !sameTenantRecord(target, safe))
|
|
129
133
|
return undefined;
|
|
130
|
-
if (
|
|
134
|
+
if (!matchesDeploymentActivation(target, precondition)) {
|
|
131
135
|
return undefined;
|
|
132
136
|
}
|
|
133
137
|
const records = await this.loadAll();
|
|
@@ -135,11 +139,16 @@ export class JsonFileArtifactStore {
|
|
|
135
139
|
const previousActive = records
|
|
136
140
|
.filter((record) => record.active && sameDeploymentScope(record, target))
|
|
137
141
|
.sort((a, b) => b.deploymentVersion - a.deploymentVersion)[0];
|
|
142
|
+
if (precondition === undefined && previousActive !== undefined) {
|
|
143
|
+
assertDeploymentAppendVersion([previousActive], { ...target, active: true });
|
|
144
|
+
}
|
|
145
|
+
assertDeploymentAppendPolicy(records, { ...target, active: true }, precondition?.expectedActivePolicy);
|
|
138
146
|
const alreadyActive = previousActive?.deploymentId === target.deploymentId;
|
|
139
147
|
const activated = {
|
|
140
148
|
...target,
|
|
141
149
|
active: true,
|
|
142
|
-
...(target
|
|
150
|
+
...(requiresCustomerAuthProjection(target, precondition?.serverAuth) &&
|
|
151
|
+
precondition?.serverAuth !== undefined
|
|
143
152
|
? { serverAuth: precondition.serverAuth }
|
|
144
153
|
: {}),
|
|
145
154
|
};
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* own persistence and feed their own raw records/anchors through these pure functions so every
|
|
6
6
|
* backend groups, ranks, and sorts identically.
|
|
7
7
|
*/
|
|
8
|
+
import { requiresCustomerAuthProjection } from '../customer-auth-audience-binding.js';
|
|
8
9
|
import { sameTenantRecord } from '../deployment-versioning.js';
|
|
9
10
|
import { deploymentOwnerSubject } from '../registry-helpers.js';
|
|
10
11
|
import { validateSlug } from './validate.js';
|
|
@@ -139,17 +140,29 @@ export function resolveActiveAccessUpdate(record, ref, input) {
|
|
|
139
140
|
record.archivedAt !== undefined ||
|
|
140
141
|
!sameTenantRecord(record, ref) ||
|
|
141
142
|
record.accessMode !== input.expectedAccessMode ||
|
|
143
|
+
record.schemaVersion !== (input.expectedSchemaVersion ?? 1) ||
|
|
144
|
+
(input.expectedManifest !== undefined && record.manifest !== input.expectedManifest) ||
|
|
142
145
|
deploymentOwnerSubject(record) !== input.expectedOwnerSubject)
|
|
143
146
|
return undefined;
|
|
144
147
|
if ((record.accessMode ?? 'owner-only') === input.accessMode &&
|
|
148
|
+
(input.schemaVersion === undefined || record.schemaVersion === input.schemaVersion) &&
|
|
145
149
|
(input.ownerSubject === undefined || deploymentOwnerSubject(record) === input.ownerSubject) &&
|
|
146
|
-
|
|
150
|
+
!requiresCustomerAuthProjection({
|
|
151
|
+
...record,
|
|
152
|
+
accessMode: input.accessMode,
|
|
153
|
+
schemaVersion: input.schemaVersion ?? record.schemaVersion,
|
|
154
|
+
}, input.serverAuth))
|
|
147
155
|
return record;
|
|
148
156
|
return {
|
|
149
157
|
...record,
|
|
150
158
|
accessMode: input.accessMode,
|
|
159
|
+
schemaVersion: input.schemaVersion ?? record.schemaVersion,
|
|
151
160
|
...(input.ownerSubject !== undefined ? { ownerSubject: input.ownerSubject } : {}),
|
|
152
|
-
...(
|
|
161
|
+
...(requiresCustomerAuthProjection({
|
|
162
|
+
...record,
|
|
163
|
+
accessMode: input.accessMode,
|
|
164
|
+
schemaVersion: input.schemaVersion ?? record.schemaVersion,
|
|
165
|
+
}, input.serverAuth) && input.serverAuth !== undefined
|
|
153
166
|
? { serverAuth: input.serverAuth }
|
|
154
167
|
: {}),
|
|
155
168
|
};
|
|
@@ -3,7 +3,7 @@ import type { OrganizationStore } from '@noodle-borg/control-plane/portable';
|
|
|
3
3
|
import type { OrgMembershipSource } from '@noodle-borg/module';
|
|
4
4
|
import type { SealedSecret } from '@noodle-borg/runtime';
|
|
5
5
|
import type { AccessMode } from '@noodle-borg/transport-http';
|
|
6
|
-
import type { DeploymentSource } from '@noodle-borg/wire-contracts';
|
|
6
|
+
import type { DeploymentAuthentication, DeploymentSource } from '@noodle-borg/wire-contracts';
|
|
7
7
|
import type { AppPackageSnapshotV1 } from './app-package-snapshot.js';
|
|
8
8
|
import type { ProductionEnvironmentChange } from './store/environment-production.js';
|
|
9
9
|
export type { ActiveMcpSubdomainClaim, ChangeMcpSubdomainInput, CreateOrgWithOwnerInput, McpSubdomainMutationResult, McpSubdomainSetting, OrgDomainRecord, OrgInvitationRecord, OrgMemberRecord, OrgOpenAIAppsChallengeRecord, OrgRecord, OrgRole, PersonalWorkspaceProvisionInput, PersonalWorkspaceProvisionResult, SignupAllowlistKind, SignupAllowlistRecord, WelcomeEmailRecord, } from '@noodle-borg/control-plane/portable';
|
|
@@ -33,7 +33,7 @@ export type SecretEnvelope = {
|
|
|
33
33
|
* of the source strings, so the inputs + identity are a faithful, reproducible record.
|
|
34
34
|
*/
|
|
35
35
|
export interface DeployRecord {
|
|
36
|
-
/** Record format version
|
|
36
|
+
/** Record format version; customer mixed adoption writes 2, which remains sticky on new records. */
|
|
37
37
|
readonly schemaVersion: number;
|
|
38
38
|
readonly deploymentId: string;
|
|
39
39
|
readonly orgSlug: string;
|
|
@@ -241,6 +241,7 @@ export interface DeploymentStatus {
|
|
|
241
241
|
readonly createdByEmail?: string;
|
|
242
242
|
readonly ownerSubject?: string;
|
|
243
243
|
readonly accessMode: AccessMode;
|
|
244
|
+
readonly authentication?: DeploymentAuthentication;
|
|
244
245
|
readonly deploymentLock?: DeploymentLockMetadata;
|
|
245
246
|
};
|
|
246
247
|
readonly health: {
|
|
@@ -257,11 +258,29 @@ export interface DeploymentActivationResult {
|
|
|
257
258
|
readonly alreadyActive: boolean;
|
|
258
259
|
}
|
|
259
260
|
/** One atomic access/owner compare-and-set over the active deployment's observed state. */
|
|
261
|
+
export interface DeploymentPolicyPrecondition {
|
|
262
|
+
readonly active: Pick<DeployRecord, 'deploymentId' | 'schemaVersion' | 'accessMode' | 'ownerSubject' | 'manifest' | 'serverAuth'> | null;
|
|
263
|
+
}
|
|
264
|
+
/** The source and authority validated before atomically activating this exact target revision. */
|
|
265
|
+
export interface DeploymentActivationPrecondition {
|
|
266
|
+
readonly expectedAccessMode: AccessMode | undefined;
|
|
267
|
+
/** Older callers are restricted to schema-1 targets. */
|
|
268
|
+
readonly expectedSchemaVersion?: number;
|
|
269
|
+
readonly expectedRevision?: Pick<DeployRecord, 'manifest' | 'connectors' | 'hostedAssets' | 'serverAuth' | 'serverVersion' | 'ownerSubject' | 'createdBySubject' | 'orgMembershipSources' | 'archivedAt'>;
|
|
270
|
+
readonly expectedActivePolicy?: DeploymentPolicyPrecondition;
|
|
271
|
+
/** Compiler-authoritative projection, applied only after revision validation. */
|
|
272
|
+
readonly serverAuth?: TenantAuthConfig;
|
|
273
|
+
}
|
|
260
274
|
export interface ActiveAccessUpdateInput {
|
|
275
|
+
/** Internal policy adoption; callers cannot author a deployment schema version. */
|
|
276
|
+
readonly schemaVersion?: 2;
|
|
261
277
|
readonly accessMode: AccessMode;
|
|
262
278
|
/** Desired owner mutation. Omission preserves the current effective owner; clearing is unsupported. */
|
|
263
279
|
readonly ownerSubject?: string;
|
|
264
280
|
readonly expectedAccessMode: AccessMode | undefined;
|
|
281
|
+
/** Older callers omit this and are restricted to version-1 records. */
|
|
282
|
+
readonly expectedSchemaVersion?: number;
|
|
283
|
+
readonly expectedManifest?: string;
|
|
265
284
|
readonly expectedOwnerSubject: string | undefined;
|
|
266
285
|
/** Compiler-authoritative projection persisted atomically when enabling customer access. */
|
|
267
286
|
readonly serverAuth?: TenantAuthConfig;
|
|
@@ -283,7 +302,7 @@ export interface ControlPlaneStore extends OrganizationStore {
|
|
|
283
302
|
* an earlier deployment without changing the tenant-facing URL.
|
|
284
303
|
*/
|
|
285
304
|
export interface ArtifactStore {
|
|
286
|
-
append(record: DeployRecord): Promise<void>;
|
|
305
|
+
append(record: DeployRecord, precondition?: DeploymentPolicyPrecondition): Promise<void>;
|
|
287
306
|
loadAll(): Promise<readonly DeployRecord[]>;
|
|
288
307
|
/**
|
|
289
308
|
* Fetch one server's record by id, or `undefined` if absent. A point read used by lazy
|
|
@@ -301,11 +320,7 @@ export interface ArtifactStore {
|
|
|
301
320
|
* bindings. Implementations may optimize this security lookup; registries fall back to `loadAll`.
|
|
302
321
|
*/
|
|
303
322
|
findActiveCustomerAuthAudienceConflict?(ref: TenantRef, auth: TenantAuthConfig): Promise<TenantRef | undefined>;
|
|
304
|
-
activateDeployment(ref: TenantRef, deploymentId: string, precondition?: {
|
|
305
|
-
readonly expectedAccessMode: AccessMode | undefined;
|
|
306
|
-
/** Compiler-authoritative projection persisted atomically when activating customer access. */
|
|
307
|
-
readonly serverAuth?: TenantAuthConfig;
|
|
308
|
-
}, options?: {
|
|
323
|
+
activateDeployment(ref: TenantRef, deploymentId: string, precondition?: DeploymentActivationPrecondition, options?: {
|
|
309
324
|
readonly automationId?: string;
|
|
310
325
|
}): Promise<DeploymentActivationResult | undefined>;
|
|
311
326
|
/**
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
41
41
|
"@noodle-borg/admission-limits": "0.0.0",
|
|
42
|
-
"@noodle-borg/agent-kit": "0.
|
|
42
|
+
"@noodle-borg/agent-kit": "0.102.0",
|
|
43
43
|
"@noodle-borg/app-package": "0.0.0",
|
|
44
44
|
"@noodle-borg/assistant-gateway": "0.0.0",
|
|
45
45
|
"@noodle-borg/auth": "0.0.0",
|
|
@@ -5,6 +5,7 @@ import { type TlsPosture } from './front-door.js';
|
|
|
5
5
|
import { type Logger } from './logging.js';
|
|
6
6
|
import { type PublicTenantRouting } from './routing.js';
|
|
7
7
|
import type { HostedToolAuthorizationObserver } from './service-principal-authorization.js';
|
|
8
|
+
import { type TargetAuthentication } from './target-authentication.js';
|
|
8
9
|
import type { HostedToolDispatchHook } from './tool-dispatch.js';
|
|
9
10
|
export type { AccessMode, AdmissionCategory, AdmissionContext, AdmissionDecision, AdmissionGate, DataPlaneAuthorizationResult, DataPlaneIdentityAuthorizer, OwnerTokenVerifier, TenantRouteRef, } from '@noodle-borg/module';
|
|
10
11
|
export type { PublicTenantRouting } from './routing.js';
|
|
@@ -78,9 +79,7 @@ export interface ServedTarget {
|
|
|
78
79
|
readonly app?: string;
|
|
79
80
|
readonly environment?: string;
|
|
80
81
|
readonly orgMembershipSources?: readonly OrgMembershipSource[];
|
|
81
|
-
readonly
|
|
82
|
-
readonly authServerIssuer?: string;
|
|
83
|
-
readonly authServerIssuers?: readonly string[];
|
|
82
|
+
readonly authentication?: TargetAuthentication;
|
|
84
83
|
readonly intentCaptureMode?: IntentCaptureMode;
|
|
85
84
|
}
|
|
86
85
|
export type ServerLookup = (deploymentId: string) => Promise<ServedTarget | undefined>;
|
|
@@ -4,6 +4,7 @@ import { noopLogger } from './logging.js';
|
|
|
4
4
|
import { guard, logRequest, rpcError, sendJson } from './responses.js';
|
|
5
5
|
import { resolveRoute } from './routing.js';
|
|
6
6
|
import { serveRequest } from './serve-request.js';
|
|
7
|
+
import { resolveTargetAuthentication } from './target-authentication.js';
|
|
7
8
|
const DEFAULT_ENDPOINT = '/mcp';
|
|
8
9
|
const DEFAULT_MAX_BODY = 1 << 20;
|
|
9
10
|
/** Build the single-artifact raw-Node security front door. */
|
|
@@ -33,7 +34,7 @@ export function createMcpHttpHandler(target, options = {}) {
|
|
|
33
34
|
app: undefined,
|
|
34
35
|
environment: undefined,
|
|
35
36
|
orgMembershipSources: undefined,
|
|
36
|
-
|
|
37
|
+
authentication: resolveTargetAuthentication({}, options.verifyOwnerToken),
|
|
37
38
|
authorizeDataPlaneIdentity: options.authorizeDataPlaneIdentity,
|
|
38
39
|
admissionGate: options.admissionGate,
|
|
39
40
|
captureRequestEvent: options.captureRequestEvent,
|
|
@@ -101,9 +102,7 @@ export function createMcpRouter(lookup, options = {}) {
|
|
|
101
102
|
ownerSubject: resolvedTarget.ownerSubject,
|
|
102
103
|
org: resolvedTarget.org,
|
|
103
104
|
orgMembershipSources: resolvedTarget.orgMembershipSources,
|
|
104
|
-
|
|
105
|
-
? resolvedTarget.verifyToken
|
|
106
|
-
: (resolvedTarget.verifyToken ?? options.verifyOwnerToken),
|
|
105
|
+
authentication: resolveTargetAuthentication(resolvedTarget, options.verifyOwnerToken),
|
|
107
106
|
authorizeDataPlaneIdentity: options.authorizeDataPlaneIdentity,
|
|
108
107
|
admissionGate: options.admissionGate,
|
|
109
108
|
captureRequestEvent: options.captureRequestEvent,
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
import type { AccessMode, DataPlaneIdentityAuthorizer, OrgMembershipSource
|
|
2
|
+
import type { AccessMode, DataPlaneIdentityAuthorizer, OrgMembershipSource } from '@noodle-borg/module';
|
|
3
3
|
import { type ProtocolRequestContext } from '@noodle-borg/protocol';
|
|
4
|
+
import type { TargetAuthentication } from './target-authentication.js';
|
|
4
5
|
export interface IdentityAuthorizationOptions {
|
|
5
6
|
readonly accessMode: AccessMode | undefined;
|
|
6
7
|
readonly ownerSubject: string | undefined;
|
|
7
8
|
readonly org: string | undefined;
|
|
8
9
|
readonly orgMembershipSources: readonly OrgMembershipSource[] | undefined;
|
|
9
|
-
readonly
|
|
10
|
+
readonly authentication: TargetAuthentication;
|
|
10
11
|
readonly authorizeDataPlaneIdentity: DataPlaneIdentityAuthorizer | undefined;
|
|
11
12
|
/** Whether to trust forwarded-proto when reconstructing the public resource/PRM URLs. */
|
|
12
13
|
readonly trustProxy: boolean;
|
|
@@ -9,13 +9,13 @@ import { header } from './request-capture.js';
|
|
|
9
9
|
export async function authorizeIdentityMode(req, res, auth) {
|
|
10
10
|
const challenge = protectedResourceMetadataUrl(req, auth);
|
|
11
11
|
const token = bearerToken(header(req, 'authorization'));
|
|
12
|
-
if (token === null || auth.
|
|
12
|
+
if (token === null || auth.authentication.verifyToken === undefined) {
|
|
13
13
|
sendUnauthorized(res, challenge);
|
|
14
14
|
return { allow: false, reason: token === null ? 'missing_token' : 'verifier_unavailable' };
|
|
15
15
|
}
|
|
16
|
-
const verification = await auth.
|
|
16
|
+
const verification = await auth.authentication.verifyToken(token, canonicalResourceUrl(req, auth));
|
|
17
17
|
if (verification === null) {
|
|
18
|
-
sendUnauthorized(res, challenge);
|
|
18
|
+
sendUnauthorized(res, challenge, 'invalid_token');
|
|
19
19
|
return { allow: false, reason: 'token_rejected' };
|
|
20
20
|
}
|
|
21
21
|
const { caller: identity } = verification;
|
|
@@ -76,27 +76,38 @@ export async function authorizeIdentityMode(req, res, auth) {
|
|
|
76
76
|
*/
|
|
77
77
|
export async function authorizePublicServiceMode(req, auth) {
|
|
78
78
|
const token = bearerToken(header(req, 'authorization'));
|
|
79
|
-
if (token === null || auth.
|
|
79
|
+
if (token === null || auth.authentication.verifyToken === undefined)
|
|
80
80
|
return { allow: true };
|
|
81
|
-
const verification = await auth.
|
|
81
|
+
const verification = await auth.authentication.verifyToken(token, canonicalResourceUrl(req, auth));
|
|
82
82
|
return verification?.caller.identityKind === 'service'
|
|
83
83
|
? { allow: true, caller: verification.caller }
|
|
84
84
|
: { allow: true };
|
|
85
85
|
}
|
|
86
86
|
export async function authorizeMixedMode(req, res, auth) {
|
|
87
|
-
const
|
|
88
|
-
if (
|
|
87
|
+
const authorization = header(req, 'authorization');
|
|
88
|
+
if (authorization === undefined)
|
|
89
89
|
return { allow: true };
|
|
90
|
+
const token = bearerToken(authorization);
|
|
90
91
|
const challenge = protectedResourceMetadataUrl(req, auth);
|
|
91
|
-
if (
|
|
92
|
+
if (token === null) {
|
|
93
|
+
sendUnauthorized(res, challenge, 'invalid_token');
|
|
94
|
+
return { allow: false, reason: 'token_rejected' };
|
|
95
|
+
}
|
|
96
|
+
if (auth.authentication.verifyToken === undefined) {
|
|
92
97
|
sendUnauthorized(res, challenge);
|
|
93
98
|
return { allow: false, reason: 'verifier_unavailable' };
|
|
94
99
|
}
|
|
95
|
-
const verification = await auth.
|
|
100
|
+
const verification = await auth.authentication.verifyToken(token, canonicalResourceUrl(req, auth));
|
|
96
101
|
if (verification === null) {
|
|
97
|
-
sendUnauthorized(res, challenge);
|
|
102
|
+
sendUnauthorized(res, challenge, 'invalid_token');
|
|
98
103
|
return { allow: false, reason: 'token_rejected' };
|
|
99
104
|
}
|
|
105
|
+
if (auth.authentication.kind === 'customer' &&
|
|
106
|
+
verification.caller.identityKind !== 'customer' &&
|
|
107
|
+
verification.caller.identityKind !== 'service') {
|
|
108
|
+
sendUnauthorized(res, challenge, 'invalid_token');
|
|
109
|
+
return { allow: false, reason: 'identity_not_customer' };
|
|
110
|
+
}
|
|
100
111
|
return {
|
|
101
112
|
allow: true,
|
|
102
113
|
caller: verification.caller,
|
|
@@ -126,13 +137,13 @@ export function bearerToken(headerValue) {
|
|
|
126
137
|
* `resourceMetadataUrl` is included so an MCP client can discover the authorization server (RFC 9728 /
|
|
127
138
|
* the MCP authorization spec).
|
|
128
139
|
*/
|
|
129
|
-
function sendUnauthorized(res, resourceMetadataUrl) {
|
|
140
|
+
function sendUnauthorized(res, resourceMetadataUrl, error) {
|
|
130
141
|
const challenge = resourceMetadataUrl !== undefined
|
|
131
142
|
? `Bearer realm="noodle", resource_metadata="${resourceMetadataUrl}"`
|
|
132
143
|
: 'Bearer realm="noodle"';
|
|
133
144
|
res.writeHead(401, {
|
|
134
145
|
'content-type': 'application/json; charset=utf-8',
|
|
135
|
-
'www-authenticate': challenge,
|
|
146
|
+
'www-authenticate': error === undefined ? challenge : `${challenge}, error="${error}"`,
|
|
136
147
|
});
|
|
137
148
|
res.end(JSON.stringify(rpcError(JSON_RPC.INVALID_REQUEST, 'unauthorized')));
|
|
138
149
|
}
|
|
@@ -8,6 +8,7 @@ export { sendJson } from './responses.js';
|
|
|
8
8
|
export { type RunningServer, type ServeOptions, serveHttp } from './serve.js';
|
|
9
9
|
export type { HostedToolAuthorizationObservation, HostedToolAuthorizationObserver, ServicePrincipalToolAuthorizationObservation, } from './service-principal-authorization.js';
|
|
10
10
|
export { preflightServicePrincipalToolCall, sendServicePrincipalToolDenial, } from './service-principal-authorization.js';
|
|
11
|
+
export type { TargetAuthentication } from './target-authentication.js';
|
|
11
12
|
export type { HostedToolDispatchContext, HostedToolDispatchHook, } from './tool-dispatch.js';
|
|
12
13
|
export { toWebRequest, writeWebResponse } from './web-bridge.js';
|
|
13
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -49,6 +49,9 @@ export async function serveRequest(req, res, target, auth, routeId, maxBody, all
|
|
|
49
49
|
// and the SDK transport is never constructed for it. A missing accessMode is reserved for loopback/local
|
|
50
50
|
// dev targets and remains open.
|
|
51
51
|
let protocolContext = {
|
|
52
|
+
...(auth.accessMode === 'mixed' && auth.authentication.kind === 'customer'
|
|
53
|
+
? { toolAuthentication: 'mixed-customer' }
|
|
54
|
+
: {}),
|
|
52
55
|
...(auth.oauthClientCredentialsReady ? { oauthClientCredentialsReady: true } : {}),
|
|
53
56
|
};
|
|
54
57
|
let subject;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AccessMode, OwnerTokenVerifier } from '@noodle-borg/module';
|
|
2
|
+
/** Resolved identity authority. A missing customer verifier must never select platform defaults. */
|
|
3
|
+
export type TargetAuthentication = {
|
|
4
|
+
readonly kind: 'platform';
|
|
5
|
+
readonly verifyToken?: OwnerTokenVerifier;
|
|
6
|
+
} | {
|
|
7
|
+
readonly kind: 'customer';
|
|
8
|
+
readonly verifyToken?: OwnerTokenVerifier;
|
|
9
|
+
readonly authorizationServers?: readonly string[];
|
|
10
|
+
};
|
|
11
|
+
export declare function resolveTargetAuthentication(target: {
|
|
12
|
+
readonly accessMode?: AccessMode;
|
|
13
|
+
readonly authentication?: TargetAuthentication;
|
|
14
|
+
}, platformVerifier?: OwnerTokenVerifier): TargetAuthentication;
|
|
15
|
+
//# sourceMappingURL=target-authentication.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function resolveTargetAuthentication(target, platformVerifier) {
|
|
2
|
+
if (target.authentication?.kind === 'customer')
|
|
3
|
+
return target.authentication;
|
|
4
|
+
if (target.accessMode === 'customers')
|
|
5
|
+
return { kind: 'customer' };
|
|
6
|
+
const verifyToken = target.authentication?.verifyToken ?? platformVerifier;
|
|
7
|
+
return { kind: 'platform', ...(verifyToken === undefined ? {} : { verifyToken }) };
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=target-authentication.js.map
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
/** Strict service-output contracts for control-plane reads and mutations (ADR 0128). */
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
+
/** Effective authority enforcing caller authentication for one deployment. */
|
|
4
|
+
export declare const deploymentAuthenticationSchema: z.ZodEnum<{
|
|
5
|
+
customer: "customer";
|
|
6
|
+
none: "none";
|
|
7
|
+
platform: "platform";
|
|
8
|
+
}>;
|
|
9
|
+
export type DeploymentAuthentication = z.infer<typeof deploymentAuthenticationSchema>;
|
|
3
10
|
/** Exact OAuth subject bound by an operator to an owner-only deployment. */
|
|
4
11
|
export declare const deploymentOwnerSubjectSchema: z.ZodString;
|
|
5
12
|
export declare const accessUpdateRequestSchema: z.ZodObject<{
|
|
@@ -32,6 +39,11 @@ export declare const accessUpdateResponseSchema: z.ZodObject<{
|
|
|
32
39
|
mixed: "mixed";
|
|
33
40
|
customers: "customers";
|
|
34
41
|
}>;
|
|
42
|
+
authentication: z.ZodOptional<z.ZodEnum<{
|
|
43
|
+
customer: "customer";
|
|
44
|
+
none: "none";
|
|
45
|
+
platform: "platform";
|
|
46
|
+
}>>;
|
|
35
47
|
ownerSubject: z.ZodOptional<z.ZodString>;
|
|
36
48
|
}, z.core.$strict>;
|
|
37
49
|
previousAccessMode: z.ZodEnum<{
|
|
@@ -45,6 +57,7 @@ export declare const accessUpdateResponseSchema: z.ZodObject<{
|
|
|
45
57
|
previousOwnerSubject: z.ZodOptional<z.ZodString>;
|
|
46
58
|
accessChanged: z.ZodBoolean;
|
|
47
59
|
ownerChanged: z.ZodBoolean;
|
|
60
|
+
policyChanged: z.ZodOptional<z.ZodBoolean>;
|
|
48
61
|
changed: z.ZodBoolean;
|
|
49
62
|
}, z.core.$strict>;
|
|
50
63
|
export type AccessUpdateResponse = z.output<typeof accessUpdateResponseSchema>;
|
|
@@ -71,6 +84,11 @@ export declare const accessUpdateClientResponseSchema: z.ZodPipe<z.ZodObject<{
|
|
|
71
84
|
mixed: "mixed";
|
|
72
85
|
customers: "customers";
|
|
73
86
|
}>;
|
|
87
|
+
authentication: z.ZodOptional<z.ZodEnum<{
|
|
88
|
+
customer: "customer";
|
|
89
|
+
none: "none";
|
|
90
|
+
platform: "platform";
|
|
91
|
+
}>>;
|
|
74
92
|
ownerSubject: z.ZodOptional<z.ZodString>;
|
|
75
93
|
}, z.core.$strip>;
|
|
76
94
|
previousAccessMode: z.ZodEnum<{
|
|
@@ -84,6 +102,7 @@ export declare const accessUpdateClientResponseSchema: z.ZodPipe<z.ZodObject<{
|
|
|
84
102
|
previousOwnerSubject: z.ZodOptional<z.ZodString>;
|
|
85
103
|
accessChanged: z.ZodOptional<z.ZodBoolean>;
|
|
86
104
|
ownerChanged: z.ZodOptional<z.ZodBoolean>;
|
|
105
|
+
policyChanged: z.ZodOptional<z.ZodBoolean>;
|
|
87
106
|
changed: z.ZodBoolean;
|
|
88
107
|
}, z.core.$strip>, z.ZodTransform<{
|
|
89
108
|
accessChanged: boolean;
|
|
@@ -97,12 +116,14 @@ export declare const accessUpdateClientResponseSchema: z.ZodPipe<z.ZodObject<{
|
|
|
97
116
|
deploymentId: string;
|
|
98
117
|
accessMode: "owner-only" | "org-members" | "authenticated" | "public" | "mixed" | "customers";
|
|
99
118
|
serverVersion?: string | undefined;
|
|
119
|
+
authentication?: "customer" | "none" | "platform" | undefined;
|
|
100
120
|
ownerSubject?: string | undefined;
|
|
101
121
|
};
|
|
102
122
|
previousAccessMode: "owner-only" | "org-members" | "authenticated" | "public" | "mixed" | "customers";
|
|
103
123
|
changed: boolean;
|
|
104
124
|
previousOwnerSubject?: string | undefined;
|
|
105
125
|
ownerChanged?: boolean | undefined;
|
|
126
|
+
policyChanged?: boolean | undefined;
|
|
106
127
|
}, {
|
|
107
128
|
ok: true;
|
|
108
129
|
target: {
|
|
@@ -114,6 +135,7 @@ export declare const accessUpdateClientResponseSchema: z.ZodPipe<z.ZodObject<{
|
|
|
114
135
|
deploymentId: string;
|
|
115
136
|
accessMode: "owner-only" | "org-members" | "authenticated" | "public" | "mixed" | "customers";
|
|
116
137
|
serverVersion?: string | undefined;
|
|
138
|
+
authentication?: "customer" | "none" | "platform" | undefined;
|
|
117
139
|
ownerSubject?: string | undefined;
|
|
118
140
|
};
|
|
119
141
|
previousAccessMode: "owner-only" | "org-members" | "authenticated" | "public" | "mixed" | "customers";
|
|
@@ -121,6 +143,7 @@ export declare const accessUpdateClientResponseSchema: z.ZodPipe<z.ZodObject<{
|
|
|
121
143
|
previousOwnerSubject?: string | undefined;
|
|
122
144
|
accessChanged?: boolean | undefined;
|
|
123
145
|
ownerChanged?: boolean | undefined;
|
|
146
|
+
policyChanged?: boolean | undefined;
|
|
124
147
|
}>>;
|
|
125
148
|
export type AccessUpdateClientResponse = z.output<typeof accessUpdateClientResponseSchema>;
|
|
126
149
|
export declare const WhoamiIdentityResponseSchema: z.ZodObject<{
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/** Strict service-output contracts for control-plane reads and mutations (ADR 0128). */
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { accessModeSchema } from './access-mode.js';
|
|
4
|
+
/** Effective authority enforcing caller authentication for one deployment. */
|
|
5
|
+
export const deploymentAuthenticationSchema = z.enum(['none', 'platform', 'customer']);
|
|
4
6
|
function containsC0OrDel(value) {
|
|
5
7
|
for (let index = 0; index < value.length; index += 1) {
|
|
6
8
|
const codeUnit = value.charCodeAt(index);
|
|
@@ -46,6 +48,7 @@ export const accessUpdateResponseSchema = z
|
|
|
46
48
|
deploymentId: z.string().min(1),
|
|
47
49
|
serverVersion: z.string().min(1).optional(),
|
|
48
50
|
accessMode: accessModeSchema,
|
|
51
|
+
authentication: deploymentAuthenticationSchema.optional(),
|
|
49
52
|
ownerSubject: deploymentOwnerSubjectSchema.optional(),
|
|
50
53
|
})
|
|
51
54
|
.strict(),
|
|
@@ -53,6 +56,7 @@ export const accessUpdateResponseSchema = z
|
|
|
53
56
|
previousOwnerSubject: deploymentOwnerSubjectSchema.optional(),
|
|
54
57
|
accessChanged: z.boolean(),
|
|
55
58
|
ownerChanged: z.boolean(),
|
|
59
|
+
policyChanged: z.boolean().optional(),
|
|
56
60
|
changed: z.boolean(),
|
|
57
61
|
})
|
|
58
62
|
.strict()
|
|
@@ -65,11 +69,19 @@ export const accessUpdateResponseSchema = z
|
|
|
65
69
|
message: 'owner-only access requires a current owner subject',
|
|
66
70
|
});
|
|
67
71
|
}
|
|
68
|
-
if (value.
|
|
72
|
+
if ((value.deployment.authentication === undefined) !== (value.policyChanged === undefined)) {
|
|
73
|
+
context.addIssue({
|
|
74
|
+
code: 'custom',
|
|
75
|
+
path: ['policyChanged'],
|
|
76
|
+
message: 'authentication and policyChanged must be present together',
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (value.changed !==
|
|
80
|
+
(value.accessChanged || value.ownerChanged || (value.policyChanged ?? false))) {
|
|
69
81
|
context.addIssue({
|
|
70
82
|
code: 'custom',
|
|
71
83
|
path: ['changed'],
|
|
72
|
-
message: 'changed must equal accessChanged || ownerChanged',
|
|
84
|
+
message: 'changed must equal accessChanged || ownerChanged || policyChanged',
|
|
73
85
|
});
|
|
74
86
|
}
|
|
75
87
|
});
|
|
@@ -90,12 +102,14 @@ export const accessUpdateClientResponseSchema = z
|
|
|
90
102
|
deploymentId: z.string().min(1),
|
|
91
103
|
serverVersion: z.string().min(1).optional(),
|
|
92
104
|
accessMode: accessModeSchema,
|
|
105
|
+
authentication: deploymentAuthenticationSchema.optional(),
|
|
93
106
|
ownerSubject: deploymentOwnerSubjectSchema.optional(),
|
|
94
107
|
}),
|
|
95
108
|
previousAccessMode: accessModeSchema,
|
|
96
109
|
previousOwnerSubject: deploymentOwnerSubjectSchema.optional(),
|
|
97
110
|
accessChanged: z.boolean().optional(),
|
|
98
111
|
ownerChanged: z.boolean().optional(),
|
|
112
|
+
policyChanged: z.boolean().optional(),
|
|
99
113
|
changed: z.boolean(),
|
|
100
114
|
})
|
|
101
115
|
.superRefine((value, context) => {
|
|
@@ -107,6 +121,20 @@ export const accessUpdateClientResponseSchema = z
|
|
|
107
121
|
message: 'accessChanged and ownerChanged must be present together',
|
|
108
122
|
});
|
|
109
123
|
}
|
|
124
|
+
if ((value.deployment.authentication === undefined) !== (value.policyChanged === undefined)) {
|
|
125
|
+
context.addIssue({
|
|
126
|
+
code: 'custom',
|
|
127
|
+
path: ['policyChanged'],
|
|
128
|
+
message: 'authentication and policyChanged must be present together',
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (value.policyChanged !== undefined && !modernComponents) {
|
|
132
|
+
context.addIssue({
|
|
133
|
+
code: 'custom',
|
|
134
|
+
path: ['policyChanged'],
|
|
135
|
+
message: 'policyChanged requires accessChanged and ownerChanged',
|
|
136
|
+
});
|
|
137
|
+
}
|
|
110
138
|
if (modernComponents &&
|
|
111
139
|
value.deployment.accessMode === 'owner-only' &&
|
|
112
140
|
value.deployment.ownerSubject === undefined) {
|
|
@@ -116,11 +144,13 @@ export const accessUpdateClientResponseSchema = z
|
|
|
116
144
|
message: 'owner-only access requires a current owner subject',
|
|
117
145
|
});
|
|
118
146
|
}
|
|
119
|
-
if (modernComponents &&
|
|
147
|
+
if (modernComponents &&
|
|
148
|
+
value.changed !==
|
|
149
|
+
(value.accessChanged || value.ownerChanged || (value.policyChanged ?? false))) {
|
|
120
150
|
context.addIssue({
|
|
121
151
|
code: 'custom',
|
|
122
152
|
path: ['changed'],
|
|
123
|
-
message: 'changed must equal accessChanged || ownerChanged',
|
|
153
|
+
message: 'changed must equal accessChanged || ownerChanged || policyChanged',
|
|
124
154
|
});
|
|
125
155
|
}
|
|
126
156
|
})
|
|
@@ -124,6 +124,11 @@ export declare const deploySuccessResponseSchema: z.ZodObject<{
|
|
|
124
124
|
mixed: "mixed";
|
|
125
125
|
customers: "customers";
|
|
126
126
|
}>;
|
|
127
|
+
authentication: z.ZodOptional<z.ZodEnum<{
|
|
128
|
+
customer: "customer";
|
|
129
|
+
none: "none";
|
|
130
|
+
platform: "platform";
|
|
131
|
+
}>>;
|
|
127
132
|
ownerSubject: z.ZodOptional<z.ZodString>;
|
|
128
133
|
url: z.ZodString;
|
|
129
134
|
defaultUrl: z.ZodString;
|
|
@@ -385,4 +390,5 @@ export * from './application-connections.js';
|
|
|
385
390
|
export * from './application-onboarding.js';
|
|
386
391
|
export * from './billing-catalog.js';
|
|
387
392
|
export * from './operation-coordination.js';
|
|
393
|
+
export { MIXED_CUSTOMER_AUTH_FEATURE_VERSION, type ServiceInfoClientResponse, type ServiceInfoResponse, serviceInfoClientResponseSchema, serviceInfoResponseSchema, } from './service-info.js';
|
|
388
394
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { z } from 'zod';
|
|
11
11
|
import { accessModeSchema } from './access-mode.js';
|
|
12
|
-
import { deploymentOwnerSubjectSchema } from './control-plane.js';
|
|
12
|
+
import { deploymentAuthenticationSchema, deploymentOwnerSubjectSchema } from './control-plane.js';
|
|
13
13
|
export * from './access-mode.js';
|
|
14
14
|
export * from './app-purge-reconciliation.js';
|
|
15
15
|
export * from './application-channels.js';
|
|
@@ -92,6 +92,8 @@ export const deploySuccessResponseSchema = z.object({
|
|
|
92
92
|
deploymentId: z.string().min(1),
|
|
93
93
|
serverVersion: z.string().min(1),
|
|
94
94
|
accessMode: accessModeSchema,
|
|
95
|
+
/** Effective authority reported by capable services; absence means unknown on older services. */
|
|
96
|
+
authentication: deploymentAuthenticationSchema.optional(),
|
|
95
97
|
ownerSubject: deploymentOwnerSubjectSchema.optional(),
|
|
96
98
|
url: z.string().min(1),
|
|
97
99
|
defaultUrl: z.string().min(1),
|
|
@@ -227,4 +229,5 @@ export * from './application-connections.js';
|
|
|
227
229
|
export * from './application-onboarding.js';
|
|
228
230
|
export * from './billing-catalog.js';
|
|
229
231
|
export * from './operation-coordination.js';
|
|
232
|
+
export { MIXED_CUSTOMER_AUTH_FEATURE_VERSION, serviceInfoClientResponseSchema, serviceInfoResponseSchema, } from './service-info.js';
|
|
230
233
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const MIXED_CUSTOMER_AUTH_FEATURE_VERSION = 1;
|
|
3
|
+
/** Strict producer contract for the enabled R1 service; no configured tenant data belongs here. */
|
|
4
|
+
export declare const serviceInfoResponseSchema: z.ZodObject<{
|
|
5
|
+
developerPlugin: z.ZodOptional<z.ZodObject<{
|
|
6
|
+
mcpCapabilityVersion: z.ZodString;
|
|
7
|
+
}, z.core.$strict>>;
|
|
8
|
+
features: z.ZodObject<{
|
|
9
|
+
mixedCustomerAuth: z.ZodLiteral<1>;
|
|
10
|
+
}, z.core.$strict>;
|
|
11
|
+
ok: z.ZodLiteral<true>;
|
|
12
|
+
status: z.ZodLiteral<"ok">;
|
|
13
|
+
version: z.ZodString;
|
|
14
|
+
gitSha: z.ZodString;
|
|
15
|
+
buildTime: z.ZodString;
|
|
16
|
+
systemRelease: z.ZodOptional<z.ZodString>;
|
|
17
|
+
manifestChecksum: z.ZodOptional<z.ZodString>;
|
|
18
|
+
packageVersions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
19
|
+
compatiblePackageVersions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
20
|
+
}, z.core.$strict>;
|
|
21
|
+
/** Older services may omit features; future fields are stripped at each structured metadata layer. */
|
|
22
|
+
export declare const serviceInfoClientResponseSchema: z.ZodObject<{
|
|
23
|
+
developerPlugin: z.ZodOptional<z.ZodObject<{
|
|
24
|
+
mcpCapabilityVersion: z.ZodString;
|
|
25
|
+
}, z.core.$strip>>;
|
|
26
|
+
features: z.ZodOptional<z.ZodObject<{
|
|
27
|
+
mixedCustomerAuth: z.ZodOptional<z.ZodNumber>;
|
|
28
|
+
}, z.core.$strip>>;
|
|
29
|
+
ok: z.ZodLiteral<true>;
|
|
30
|
+
status: z.ZodLiteral<"ok">;
|
|
31
|
+
version: z.ZodString;
|
|
32
|
+
gitSha: z.ZodString;
|
|
33
|
+
buildTime: z.ZodString;
|
|
34
|
+
systemRelease: z.ZodOptional<z.ZodString>;
|
|
35
|
+
manifestChecksum: z.ZodOptional<z.ZodString>;
|
|
36
|
+
packageVersions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
37
|
+
compatiblePackageVersions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
38
|
+
}, z.core.$strip>;
|
|
39
|
+
export type ServiceInfoResponse = z.infer<typeof serviceInfoResponseSchema>;
|
|
40
|
+
export type ServiceInfoClientResponse = z.infer<typeof serviceInfoClientResponseSchema>;
|
|
41
|
+
//# sourceMappingURL=service-info.d.ts.map
|