@noodleseed/one 0.166.0 → 0.168.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.map +1 -1
- package/dist/commands/deploy-status-ops.js +16 -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/behavior-skills.js +4 -2
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +3 -3
- package/node_modules/@noodle-borg/agent-kit/dist/plugin-bootstrap-skill.js +8 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-auth-ref.js +5 -2
- package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.js +20 -0
- package/node_modules/@noodle-borg/agent-kit/dist/skill-router.js +9 -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/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/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 +2 -2
- package/node_modules/@noodle-borg/service/dist/deployment-execution.js +2 -2
- package/node_modules/@noodle-borg/service/dist/deployment-record-version.js +26 -2
- package/node_modules/@noodle-borg/service/dist/registry-access.js +33 -31
- package/node_modules/@noodle-borg/service/dist/registry-deploy-transaction.js +97 -22
- package/node_modules/@noodle-borg/service/dist/registry-rollback.js +13 -1
- package/node_modules/@noodle-borg/service/dist/registry-state.d.ts +3 -7
- package/node_modules/@noodle-borg/service/dist/registry-state.js +6 -5
- package/node_modules/@noodle-borg/service/dist/registry-status.js +3 -4
- package/node_modules/@noodle-borg/service/dist/registry-targets.js +35 -28
- package/node_modules/@noodle-borg/service/dist/registry-types.d.ts +3 -1
- package/node_modules/@noodle-borg/service/dist/registry.js +40 -39
- package/node_modules/@noodle-borg/service/dist/routes/access.js +4 -2
- 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 -8
- package/node_modules/@noodle-borg/service/dist/store/in-memory.js +6 -4
- package/node_modules/@noodle-borg/service/dist/store/json-file.d.ts +3 -8
- package/node_modules/@noodle-borg/service/dist/store/json-file.js +8 -6
- package/node_modules/@noodle-borg/service/dist/store/records.js +13 -2
- package/node_modules/@noodle-borg/service/dist/store.d.ts +19 -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/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
|
@@ -195,6 +195,7 @@ export async function handleDeploy(req, res, registry, options, maxBody, tenant,
|
|
|
195
195
|
deploymentId: result.deploymentId,
|
|
196
196
|
serverVersion: result.serverVersion,
|
|
197
197
|
accessMode: result.accessMode,
|
|
198
|
+
...(result.authentication !== undefined ? { authentication: result.authentication } : {}),
|
|
198
199
|
...(result.ownerSubject !== undefined ? { ownerSubject: result.ownerSubject } : {}),
|
|
199
200
|
url: tenantMcpUrl(base, tenant, result.serverVersion, endpointOptions),
|
|
200
201
|
defaultUrl: tenantMcpUrl(base, tenant, undefined, endpointOptions),
|
|
@@ -2,8 +2,8 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { cspFaultsInManifest } from '@noodle-borg/compiler';
|
|
3
3
|
import { readDeployBody, sendJson } from '@noodle-borg/transport-http';
|
|
4
4
|
import { DEPLOY_PREFLIGHT_CHECK_TIMEOUT_MS, deployPreflightRequestSchema, formatWireError, } from '@noodle-borg/wire-contracts';
|
|
5
|
+
import { isIdentityAccessMode } from '../deployment-access-mode.js';
|
|
5
6
|
import { manifestUsesUserRoot } from '../registry-access.js';
|
|
6
|
-
import { isIdentityAccessMode } from './access-mode.js';
|
|
7
7
|
import { authorizeDeploymentOwnerSelection, authorizeTenantControl, developerGrantRouteAccess, } from './control-plane.js';
|
|
8
8
|
// Per-process resource admission, not a tenant quota or distributed state authority.
|
|
9
9
|
const activePreflights = new WeakSet();
|
|
@@ -91,7 +91,7 @@ export async function handleDeployPreflight(req, res, registry, options, maxBody
|
|
|
91
91
|
});
|
|
92
92
|
}
|
|
93
93
|
const accessMode = parsed.accessMode ?? 'owner-only';
|
|
94
|
-
if (isIdentityAccessMode(accessMode) && identity === undefined) {
|
|
94
|
+
if (isIdentityAccessMode(accessMode, parsed.manifest) && identity === undefined) {
|
|
95
95
|
return sendJson(res, 401, {
|
|
96
96
|
code: 'deployer_identity_required',
|
|
97
97
|
error: `${accessMode} deployments require an authenticated deployer`,
|
|
@@ -44,7 +44,7 @@ export async function bridgeAuthForResource(registry, resource, allowedBaseDomai
|
|
|
44
44
|
? await registry.getActiveByTenant(tenant)
|
|
45
45
|
: await registry.getActiveByTenantVersion(tenant, tenant.serverVersion);
|
|
46
46
|
const auth = target?.served.artifact.server.auth;
|
|
47
|
-
if (auth?.kind !== 'bridge')
|
|
47
|
+
if (target?.authentication?.kind !== 'customer' || auth?.kind !== 'bridge')
|
|
48
48
|
return undefined;
|
|
49
49
|
const variables = await registry.configStore.resolveConfigValues('variable', resolveConfigScope(tenant));
|
|
50
50
|
return resolveTenantBridgeAuthVariables(auth, variables);
|
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { ActiveAccessUpdateInput, AppArchiveResult, AppRestorePrecondition, AppRestoreResult, AppSummary, ArtifactStore, DeploymentActivationResult, DeploymentListFilter, DeploymentLock, DeploymentLockUpdateResult, DeploymentSummary, DeployRecord, EnvSummary, ProductionEnvironmentChange, TenantAuthConfig, TenantRef } from '../store.js';
|
|
1
|
+
import type { ActiveAccessUpdateInput, AppArchiveResult, AppRestorePrecondition, AppRestoreResult, AppSummary, ArtifactStore, DeploymentActivationPrecondition, DeploymentActivationResult, DeploymentListFilter, DeploymentLock, DeploymentLockUpdateResult, DeploymentPolicyPrecondition, DeploymentSummary, DeployRecord, EnvSummary, ProductionEnvironmentChange, TenantAuthConfig, TenantRef } from '../store.js';
|
|
3
2
|
/** In-memory store: keeps records in a Map. Used by tests and as an explicit, non-persistent option. */
|
|
4
3
|
export declare class InMemoryArtifactStore implements ArtifactStore {
|
|
5
4
|
#private;
|
|
6
|
-
append(record: DeployRecord): Promise<void>;
|
|
5
|
+
append(record: DeployRecord, precondition?: DeploymentPolicyPrecondition): Promise<void>;
|
|
7
6
|
loadAll(): Promise<readonly DeployRecord[]>;
|
|
8
7
|
get(deploymentId: string): Promise<DeployRecord | undefined>;
|
|
9
8
|
getActiveByTenant(ref: TenantRef): Promise<DeployRecord | undefined>;
|
|
10
9
|
getActiveByTenantVersion(ref: TenantRef, serverVersion: string): Promise<DeployRecord | undefined>;
|
|
11
10
|
setDeploymentLock(ref: TenantRef, serverVersion: string, expectedDeploymentId: string, deploymentLock: DeploymentLock | undefined): Promise<DeploymentLockUpdateResult>;
|
|
12
11
|
findActiveCustomerAuthAudienceConflict(ref: TenantRef, auth: TenantAuthConfig): Promise<TenantRef | undefined>;
|
|
13
|
-
activateDeployment(ref: TenantRef, deploymentId: string, precondition?: {
|
|
14
|
-
readonly expectedAccessMode: AccessMode | undefined;
|
|
15
|
-
readonly expectedSchemaVersion?: number;
|
|
16
|
-
readonly serverAuth?: TenantAuthConfig;
|
|
17
|
-
}, _options?: {
|
|
12
|
+
activateDeployment(ref: TenantRef, deploymentId: string, precondition?: DeploymentActivationPrecondition, _options?: {
|
|
18
13
|
readonly automationId?: string;
|
|
19
14
|
}): Promise<DeploymentActivationResult | undefined>;
|
|
20
15
|
updateActiveAccess(ref: TenantRef, deploymentId: string, input: ActiveAccessUpdateInput): Promise<DeployRecord | undefined>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { normalizeServerVersion } from '@noodle-borg/module';
|
|
2
2
|
import { assertSameAppPackageSnapshot, sanitizeDeployRecordAppPackageSnapshot, } from '../app-package-snapshot.js';
|
|
3
3
|
import { assertCustomerAuthRestorePrecondition, assertUniqueActiveCustomerAuthAudienceBindings, findActiveCustomerAuthAudienceConflict, requiresCustomerAuthProjection, } from '../customer-auth-audience-binding.js';
|
|
4
|
+
import { matchesDeploymentActivation } from '../deployment-activation-precondition.js';
|
|
4
5
|
import { assertDeploymentActivationUnlocked, assertDeploymentAppendUnlocked, } from '../deployment-lock.js';
|
|
5
|
-
import { assertDeploymentAppendVersion } from '../deployment-record-version.js';
|
|
6
|
+
import { assertDeploymentAppendPolicy, assertDeploymentAppendVersion, } from '../deployment-record-version.js';
|
|
6
7
|
import { defaultActiveRecord, sameDeploymentScope, sameTenantRecord, } from '../deployment-versioning.js';
|
|
7
8
|
import { appArchivedAt, deploymentSummary, matchesDeploymentFilter, paginateAppSummaries, planAppArchive, planAppRestore, planArchivedAppSweep, preserveDeploymentOwnerState, resolveActiveAccessUpdate, resolveProductionEnvironment, summarizeApps, summarizeEnvs, validateDeploymentListFilter, withoutArchiveStamp, } from './records.js';
|
|
8
9
|
import { validateSlug, validateTenantRef } from './validate.js';
|
|
@@ -10,8 +11,9 @@ import { validateSlug, validateTenantRef } from './validate.js';
|
|
|
10
11
|
export class InMemoryArtifactStore {
|
|
11
12
|
#records = new Map();
|
|
12
13
|
#productionEnvironments = new Map();
|
|
13
|
-
async append(record) {
|
|
14
|
+
async append(record, precondition) {
|
|
14
15
|
assertDeploymentAppendVersion([...this.#records.values()], record);
|
|
16
|
+
assertDeploymentAppendPolicy([...this.#records.values()], record, precondition);
|
|
15
17
|
const existing = this.#records.get(record.deploymentId);
|
|
16
18
|
if (existing !== undefined)
|
|
17
19
|
assertSameAppPackageSnapshot(existing, record);
|
|
@@ -85,8 +87,7 @@ export class InMemoryArtifactStore {
|
|
|
85
87
|
if (target === undefined || !sameTenantRecord(target, safe))
|
|
86
88
|
return Promise.resolve(undefined);
|
|
87
89
|
assertDeploymentActivationUnlocked([...this.#records.values()], target);
|
|
88
|
-
if (target
|
|
89
|
-
(precondition !== undefined && target.accessMode !== precondition.expectedAccessMode)) {
|
|
90
|
+
if (!matchesDeploymentActivation(target, precondition)) {
|
|
90
91
|
return Promise.resolve(undefined);
|
|
91
92
|
}
|
|
92
93
|
const previousActive = [...this.#records.values()]
|
|
@@ -95,6 +96,7 @@ export class InMemoryArtifactStore {
|
|
|
95
96
|
if (precondition === undefined && previousActive !== undefined) {
|
|
96
97
|
assertDeploymentAppendVersion([previousActive], { ...target, active: true });
|
|
97
98
|
}
|
|
99
|
+
assertDeploymentAppendPolicy([...this.#records.values()], { ...target, active: true }, precondition?.expectedActivePolicy);
|
|
98
100
|
const alreadyActive = previousActive?.deploymentId === target.deploymentId;
|
|
99
101
|
const activated = {
|
|
100
102
|
...target,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { ActiveAccessUpdateInput, AppArchiveResult, AppRestorePrecondition, AppRestoreResult, AppSummary, ArtifactStore, DeploymentActivationResult, DeploymentListFilter, DeploymentLock, DeploymentLockUpdateResult, DeploymentSummary, DeployRecord, EnvSummary, ProductionEnvironmentChange, TenantAuthConfig, TenantRef } from '../store.js';
|
|
1
|
+
import type { ActiveAccessUpdateInput, AppArchiveResult, AppRestorePrecondition, AppRestoreResult, AppSummary, ArtifactStore, DeploymentActivationPrecondition, DeploymentActivationResult, DeploymentListFilter, DeploymentLock, DeploymentLockUpdateResult, DeploymentPolicyPrecondition, DeploymentSummary, DeployRecord, EnvSummary, ProductionEnvironmentChange, TenantAuthConfig, TenantRef } from '../store.js';
|
|
3
2
|
/**
|
|
4
3
|
* JSON-file store: one file per deployment at `<dataDir>/deployments/<deploymentId>.json`, written atomically
|
|
5
4
|
* (write a temp file, then `rename` over the target — no partial file is ever read). `deploymentId` is a
|
|
@@ -9,18 +8,14 @@ import type { ActiveAccessUpdateInput, AppArchiveResult, AppRestorePrecondition,
|
|
|
9
8
|
export declare class JsonFileArtifactStore implements ArtifactStore {
|
|
10
9
|
#private;
|
|
11
10
|
constructor(dataDir: string);
|
|
12
|
-
append(record: DeployRecord): Promise<void>;
|
|
11
|
+
append(record: DeployRecord, precondition?: DeploymentPolicyPrecondition): Promise<void>;
|
|
13
12
|
get(deploymentId: string): Promise<DeployRecord | undefined>;
|
|
14
13
|
getActiveByTenant(ref: TenantRef): Promise<DeployRecord | undefined>;
|
|
15
14
|
getActiveByTenantVersion(ref: TenantRef, serverVersion: string): Promise<DeployRecord | undefined>;
|
|
16
15
|
setDeploymentLock(ref: TenantRef, serverVersion: string, expectedDeploymentId: string, deploymentLock: DeploymentLock | undefined): Promise<DeploymentLockUpdateResult>;
|
|
17
16
|
findActiveCustomerAuthAudienceConflict(ref: TenantRef, auth: TenantAuthConfig): Promise<TenantRef | undefined>;
|
|
18
17
|
updateActiveAccess(ref: TenantRef, deploymentId: string, input: ActiveAccessUpdateInput): Promise<DeployRecord | undefined>;
|
|
19
|
-
activateDeployment(ref: TenantRef, deploymentId: string, precondition?:
|
|
20
|
-
readonly expectedAccessMode: AccessMode | undefined;
|
|
21
|
-
readonly expectedSchemaVersion?: number;
|
|
22
|
-
readonly serverAuth?: TenantAuthConfig;
|
|
23
|
-
}): Promise<DeploymentActivationResult | undefined>;
|
|
18
|
+
activateDeployment(ref: TenantRef, deploymentId: string, precondition?: DeploymentActivationPrecondition): Promise<DeploymentActivationResult | undefined>;
|
|
24
19
|
loadAll(): Promise<readonly DeployRecord[]>;
|
|
25
20
|
listDeployments(filter: DeploymentListFilter): Promise<readonly DeploymentSummary[]>;
|
|
26
21
|
getAppArchivedAt(org: string, app: string): Promise<string | undefined>;
|
|
@@ -4,8 +4,9 @@ import { join } from 'node:path';
|
|
|
4
4
|
import { normalizeServerVersion } from '@noodle-borg/module';
|
|
5
5
|
import { assertSameAppPackageSnapshot, sanitizeDeployRecordAppPackageSnapshot, } from '../app-package-snapshot.js';
|
|
6
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';
|
|
8
|
-
import { assertDeploymentAppendVersion } from '../deployment-record-version.js';
|
|
9
|
+
import { assertDeploymentAppendPolicy, assertDeploymentAppendVersion, } from '../deployment-record-version.js';
|
|
9
10
|
import { defaultActiveRecord, sameDeploymentScope, sameTenantRecord, } from '../deployment-versioning.js';
|
|
10
11
|
import { appArchivedAt, deploymentSummary, matchesDeploymentFilter, paginateAppSummaries, planAppArchive, planAppRestore, planArchivedAppSweep, preserveDeploymentOwnerState, resolveActiveAccessUpdate, resolveProductionEnvironment, summarizeApps, summarizeEnvs, validateDeploymentListFilter, withoutArchiveStamp, } from './records.js';
|
|
11
12
|
import { DEPLOYMENT_ID_PATTERN, validateSlug, validateTenantRef } from './validate.js';
|
|
@@ -23,10 +24,10 @@ export class JsonFileArtifactStore {
|
|
|
23
24
|
this.#dir = join(dataDir, 'deployments');
|
|
24
25
|
this.#environmentMetadataDir = join(dataDir, 'environment-metadata');
|
|
25
26
|
}
|
|
26
|
-
append(record) {
|
|
27
|
-
return this.#serializeLifecycle(() => this.#appendUnlocked(record));
|
|
27
|
+
append(record, precondition) {
|
|
28
|
+
return this.#serializeLifecycle(() => this.#appendUnlocked(record, precondition));
|
|
28
29
|
}
|
|
29
|
-
async #appendUnlocked(record) {
|
|
30
|
+
async #appendUnlocked(record, precondition) {
|
|
30
31
|
// Defence in depth: `deploymentId` becomes a filename, so reject anything outside the minted shape
|
|
31
32
|
// (`mintDeploymentId` only ever produces `[a-z0-9-]`). Guards this public class against a caller that
|
|
32
33
|
// passes an untrusted id (no path traversal, no escaping the data dir).
|
|
@@ -36,6 +37,7 @@ export class JsonFileArtifactStore {
|
|
|
36
37
|
}
|
|
37
38
|
const records = await this.loadAll();
|
|
38
39
|
assertDeploymentAppendVersion(records, record);
|
|
40
|
+
assertDeploymentAppendPolicy(records, record, precondition);
|
|
39
41
|
const existing = records.find((candidate) => candidate.deploymentId === record.deploymentId);
|
|
40
42
|
if (existing !== undefined)
|
|
41
43
|
assertSameAppPackageSnapshot(existing, record);
|
|
@@ -129,8 +131,7 @@ export class JsonFileArtifactStore {
|
|
|
129
131
|
const target = await this.get(deploymentId);
|
|
130
132
|
if (target === undefined || !sameTenantRecord(target, safe))
|
|
131
133
|
return undefined;
|
|
132
|
-
if (target
|
|
133
|
-
(precondition !== undefined && target.accessMode !== precondition.expectedAccessMode)) {
|
|
134
|
+
if (!matchesDeploymentActivation(target, precondition)) {
|
|
134
135
|
return undefined;
|
|
135
136
|
}
|
|
136
137
|
const records = await this.loadAll();
|
|
@@ -141,6 +142,7 @@ export class JsonFileArtifactStore {
|
|
|
141
142
|
if (precondition === undefined && previousActive !== undefined) {
|
|
142
143
|
assertDeploymentAppendVersion([previousActive], { ...target, active: true });
|
|
143
144
|
}
|
|
145
|
+
assertDeploymentAppendPolicy(records, { ...target, active: true }, precondition?.expectedActivePolicy);
|
|
144
146
|
const alreadyActive = previousActive?.deploymentId === target.deploymentId;
|
|
145
147
|
const activated = {
|
|
146
148
|
...target,
|
|
@@ -141,17 +141,28 @@ export function resolveActiveAccessUpdate(record, ref, input) {
|
|
|
141
141
|
!sameTenantRecord(record, ref) ||
|
|
142
142
|
record.accessMode !== input.expectedAccessMode ||
|
|
143
143
|
record.schemaVersion !== (input.expectedSchemaVersion ?? 1) ||
|
|
144
|
+
(input.expectedManifest !== undefined && record.manifest !== input.expectedManifest) ||
|
|
144
145
|
deploymentOwnerSubject(record) !== input.expectedOwnerSubject)
|
|
145
146
|
return undefined;
|
|
146
147
|
if ((record.accessMode ?? 'owner-only') === input.accessMode &&
|
|
148
|
+
(input.schemaVersion === undefined || record.schemaVersion === input.schemaVersion) &&
|
|
147
149
|
(input.ownerSubject === undefined || deploymentOwnerSubject(record) === input.ownerSubject) &&
|
|
148
|
-
!requiresCustomerAuthProjection({
|
|
150
|
+
!requiresCustomerAuthProjection({
|
|
151
|
+
...record,
|
|
152
|
+
accessMode: input.accessMode,
|
|
153
|
+
schemaVersion: input.schemaVersion ?? record.schemaVersion,
|
|
154
|
+
}, input.serverAuth))
|
|
149
155
|
return record;
|
|
150
156
|
return {
|
|
151
157
|
...record,
|
|
152
158
|
accessMode: input.accessMode,
|
|
159
|
+
schemaVersion: input.schemaVersion ?? record.schemaVersion,
|
|
153
160
|
...(input.ownerSubject !== undefined ? { ownerSubject: input.ownerSubject } : {}),
|
|
154
|
-
...(requiresCustomerAuthProjection({
|
|
161
|
+
...(requiresCustomerAuthProjection({
|
|
162
|
+
...record,
|
|
163
|
+
accessMode: input.accessMode,
|
|
164
|
+
schemaVersion: input.schemaVersion ?? record.schemaVersion,
|
|
165
|
+
}, input.serverAuth) && input.serverAuth !== undefined
|
|
155
166
|
? { serverAuth: input.serverAuth }
|
|
156
167
|
: {}),
|
|
157
168
|
};
|
|
@@ -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;
|
|
@@ -258,13 +258,29 @@ export interface DeploymentActivationResult {
|
|
|
258
258
|
readonly alreadyActive: boolean;
|
|
259
259
|
}
|
|
260
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
|
+
}
|
|
261
274
|
export interface ActiveAccessUpdateInput {
|
|
275
|
+
/** Internal policy adoption; callers cannot author a deployment schema version. */
|
|
276
|
+
readonly schemaVersion?: 2;
|
|
262
277
|
readonly accessMode: AccessMode;
|
|
263
278
|
/** Desired owner mutation. Omission preserves the current effective owner; clearing is unsupported. */
|
|
264
279
|
readonly ownerSubject?: string;
|
|
265
280
|
readonly expectedAccessMode: AccessMode | undefined;
|
|
266
281
|
/** Older callers omit this and are restricted to version-1 records. */
|
|
267
282
|
readonly expectedSchemaVersion?: number;
|
|
283
|
+
readonly expectedManifest?: string;
|
|
268
284
|
readonly expectedOwnerSubject: string | undefined;
|
|
269
285
|
/** Compiler-authoritative projection persisted atomically when enabling customer access. */
|
|
270
286
|
readonly serverAuth?: TenantAuthConfig;
|
|
@@ -286,7 +302,7 @@ export interface ControlPlaneStore extends OrganizationStore {
|
|
|
286
302
|
* an earlier deployment without changing the tenant-facing URL.
|
|
287
303
|
*/
|
|
288
304
|
export interface ArtifactStore {
|
|
289
|
-
append(record: DeployRecord): Promise<void>;
|
|
305
|
+
append(record: DeployRecord, precondition?: DeploymentPolicyPrecondition): Promise<void>;
|
|
290
306
|
loadAll(): Promise<readonly DeployRecord[]>;
|
|
291
307
|
/**
|
|
292
308
|
* Fetch one server's record by id, or `undefined` if absent. A point read used by lazy
|
|
@@ -304,12 +320,7 @@ export interface ArtifactStore {
|
|
|
304
320
|
* bindings. Implementations may optimize this security lookup; registries fall back to `loadAll`.
|
|
305
321
|
*/
|
|
306
322
|
findActiveCustomerAuthAudienceConflict?(ref: TenantRef, auth: TenantAuthConfig): Promise<TenantRef | undefined>;
|
|
307
|
-
activateDeployment(ref: TenantRef, deploymentId: string, precondition?: {
|
|
308
|
-
readonly expectedAccessMode: AccessMode | undefined;
|
|
309
|
-
readonly expectedSchemaVersion?: number;
|
|
310
|
-
/** Compiler-authoritative projection persisted atomically when activating customer access. */
|
|
311
|
-
readonly serverAuth?: TenantAuthConfig;
|
|
312
|
-
}, options?: {
|
|
323
|
+
activateDeployment(ref: TenantRef, deploymentId: string, precondition?: DeploymentActivationPrecondition, options?: {
|
|
313
324
|
readonly automationId?: string;
|
|
314
325
|
}): Promise<DeploymentActivationResult | undefined>;
|
|
315
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.104.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
|
|
@@ -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
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const MIXED_CUSTOMER_AUTH_FEATURE_VERSION = 1;
|
|
3
|
+
const buildInfoShape = {
|
|
4
|
+
ok: z.literal(true),
|
|
5
|
+
status: z.literal('ok'),
|
|
6
|
+
version: z.string(),
|
|
7
|
+
gitSha: z.string(),
|
|
8
|
+
buildTime: z.string(),
|
|
9
|
+
systemRelease: z.string().optional(),
|
|
10
|
+
manifestChecksum: z.string().optional(),
|
|
11
|
+
packageVersions: z.record(z.string(), z.string()).optional(),
|
|
12
|
+
compatiblePackageVersions: z.record(z.string(), z.array(z.string())).optional(),
|
|
13
|
+
};
|
|
14
|
+
/** Strict producer contract for the enabled R1 service; no configured tenant data belongs here. */
|
|
15
|
+
export const serviceInfoResponseSchema = z.strictObject({
|
|
16
|
+
...buildInfoShape,
|
|
17
|
+
developerPlugin: z.strictObject({ mcpCapabilityVersion: z.string().min(1) }).optional(),
|
|
18
|
+
features: z.strictObject({ mixedCustomerAuth: z.literal(MIXED_CUSTOMER_AUTH_FEATURE_VERSION) }),
|
|
19
|
+
});
|
|
20
|
+
/** Older services may omit features; future fields are stripped at each structured metadata layer. */
|
|
21
|
+
export const serviceInfoClientResponseSchema = z.object({
|
|
22
|
+
...buildInfoShape,
|
|
23
|
+
developerPlugin: z.object({ mcpCapabilityVersion: z.string().min(1) }).optional(),
|
|
24
|
+
features: z.object({ mixedCustomerAuth: z.number().int().positive().optional() }).optional(),
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=service-info.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noodleseed/one",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.168.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Noodle CLI by Noodle Seed — author, run, and deploy declarative MCP servers. Embedding the assistant in your own web app is @noodleseed/assistant.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -235,7 +235,7 @@
|
|
|
235
235
|
"@modelcontextprotocol/client": "2.0.0",
|
|
236
236
|
"@modelcontextprotocol/server": "2.0.0",
|
|
237
237
|
"@noodle-borg/admission-limits": "0.0.0",
|
|
238
|
-
"@noodle-borg/agent-kit": "0.
|
|
238
|
+
"@noodle-borg/agent-kit": "0.104.0",
|
|
239
239
|
"@noodle-borg/app-audit": "0.0.0",
|
|
240
240
|
"@noodle-borg/app-package": "0.0.0",
|
|
241
241
|
"@noodle-borg/assistant-gateway": "0.0.0",
|