docs(platform): align connector, EDP, and deploy canon
This commit is contained in:
+119
-16
@@ -97,8 +97,15 @@ Engine-owned activator may select it after exact MCP schema acceptance.
|
||||
|
||||
The paired Engine activation is built by
|
||||
`build-engine-n8n-private-extension-artifact.mjs`. It deliberately does not
|
||||
copy the dirty Engine `docker-compose.yml` and does not build an image. Instead
|
||||
it installs a narrowly scoped Compose override plus a strict transition
|
||||
copy from or write generated files into the dirty Engine worktree, and it does
|
||||
not build an image. A fresh transition id is mandatory and previously issued
|
||||
ids are rejected:
|
||||
|
||||
```bash
|
||||
node infra/deploy-runner/build-engine-n8n-private-extension-artifact.mjs 20260717-004
|
||||
```
|
||||
|
||||
The builder emits a narrowly scoped Compose override plus a strict transition
|
||||
descriptor. On apply, the runner validates the staged release again, verifies
|
||||
that the running n8n container and the NAS-local `2.3.2` tag resolve to the
|
||||
same immutable image ID, and extracts the package into the root-owned,
|
||||
@@ -110,10 +117,15 @@ read-only Engine release tree:
|
||||
|
||||
The override sets `N8N_USER_FOLDER=/home/node`, which is required because the
|
||||
actual Engine service runs as root while the canonical community package path
|
||||
is below `/home/node/.n8n`. It enables loading but disables reinstall, mounts
|
||||
only the exact release read-only, and uses both Compose `pull_policy: never`
|
||||
and `docker compose up --pull never`. No registry access, lifecycle script,
|
||||
database `installed_packages` row or custom-extension loader is involved.
|
||||
is below `/home/node/.n8n`. The live runtime contract remains the successfully
|
||||
deployed generation-003 contract and does not set `NODE_PATH`. Only the
|
||||
runner's isolated `node -e` package-loader probe temporarily initializes the
|
||||
dependency tree bundled inside the exact n8n base image; this reproduces n8n's
|
||||
own loader without redefining the live Compose state. The override enables
|
||||
loading but disables reinstall, mounts only the exact release read-only, and
|
||||
uses both Compose `pull_policy: never` and `docker compose up --pull never`.
|
||||
No registry access, lifecycle script, database `installed_packages` row or
|
||||
custom-extension loader is involved.
|
||||
|
||||
The runner pins the exact Engine service topology observed in source and
|
||||
rejects an added worker/webhook generation. Only the single actual `n8n`
|
||||
@@ -140,20 +152,106 @@ PYTHONDONTWRITEBYTECODE=1 \
|
||||
```
|
||||
|
||||
For `platform` artifacts, the allowlist includes the versioned Ontology Core,
|
||||
the legacy Gelios experiment and the provider-neutral External Data Plane
|
||||
sources. An External Data Plane artifact builds only its image and starts
|
||||
`external-data-plane-postgres` plus `external-data-plane`; it never contains a
|
||||
provider credential, provider endpoint, collection schedule or command
|
||||
transport. Database credentials remain root-owned live `.env.synology`
|
||||
the frozen legacy Gelios compatibility service, and the provider-neutral
|
||||
External Data Plane sources. The Gelios service remains reproducible only to
|
||||
protect its existing database/workflow; it is not a template for a provider
|
||||
integration. An External Data Plane artifact builds only its image and
|
||||
force-recreates only `external-data-plane`; the already healthy
|
||||
`external-data-plane-postgres` container and its Timescale volume are an
|
||||
independent deploy prerequisite and are never selected by an EDP application
|
||||
artifact. The reviewed Compose source pins the Timescale image, named volume
|
||||
and target, internal database-only network, absence of database host ports,
|
||||
healthy dependency, localhost-only EDP bind and the two read-only
|
||||
provisioner/trust mounts in the reviewed Compose source. The runner does not
|
||||
reinterpret version-dependent `docker compose config` JSON as a second deploy
|
||||
schema. Its canonical enforcement remains the artifact/path allowlist plus
|
||||
hard-coded build command, selected service set, runtime-secret preparation and
|
||||
health acceptance. Post-apply acceptance also requires
|
||||
`database=ready`; a first-rollout failure removes only the candidate EDP
|
||||
container without volumes and restores the source overlay. It never contains a
|
||||
provider credential, provider endpoint,
|
||||
collection schedule or command
|
||||
transport. Its contract payload is an exact provider-neutral runtime subset;
|
||||
`providers/*`, mappings, fixtures and tests are excluded and do not trigger an
|
||||
EDP rebuild. Database credentials remain root-owned live `.env.synology`
|
||||
configuration and must not reuse `NODEDC_INTERNAL_ACCESS_TOKEN`.
|
||||
|
||||
The External Data Plane writer-provisioner credential is different: on the
|
||||
first relevant Platform apply, the root-owned runner creates
|
||||
On the first relevant Platform apply, the root-owned runner creates
|
||||
`/volume1/docker/nodedc-platform/secrets/external-data-plane-provisioner/token`
|
||||
atomically in a dedicated UID/GID `11006` directory (directory `0500`, token
|
||||
`0400`). It is never an `.env` value or an artifact member; Compose mounts it
|
||||
read-only only into External Data Plane and, when implemented, its dedicated
|
||||
Engine provisioner running under the same restricted identity.
|
||||
`0400`). It is never an `.env` value or an artifact member and is mounted
|
||||
read-only only into External Data Plane.
|
||||
|
||||
Manual one-time binding issuance and digest-only managed writer ensure are
|
||||
independently disabled by default. The target control-plane operation generates
|
||||
and stores the capability inside native NDC L2 Credentials and sends only its
|
||||
digest to EDP; users and MCP consumers receive only an opaque compatible
|
||||
reference/status. The runner-owned bearer above authenticates only legacy
|
||||
plaintext issuance and is intentionally rejected by managed ensure/revoke.
|
||||
Managed requests use a deployment Ed25519 Engine service key; EDP mounts only
|
||||
the public-key trust directory read-only. On every reviewed Engine apply and on
|
||||
an EDP runtime apply, this runner creates or validates one matching Ed25519 pair:
|
||||
the Engine-only private key is `root:root 0400`, while the EDP trust copy is
|
||||
`root:11006 0440`. Public-only crash state, key mismatch, a non-Ed25519 key,
|
||||
symlinks and permissive modes fail closed. `plan` discloses both paths without
|
||||
printing key material. The private key must not be broadened into an L2 graph,
|
||||
MCP surface, artifact or shared-token boundary.
|
||||
|
||||
The reviewed Engine source candidate has dedicated server-derived MCP
|
||||
plan/apply handling for the exact `ndcDataProductWriterApi` + Data Product
|
||||
Publish tuple. It is separate from the generic HTTP safe-ref path and accepts no
|
||||
caller-provided provider/scope/credential identity, capability, generation or
|
||||
service URL. The production managed flag remains false during staging. In the
|
||||
explicitly confirmed activation window it is set to true immediately before
|
||||
the Platform EDP artifact; runner acceptance then requires EDP `/healthz` to
|
||||
report managed provisioning `enabled`. At that point the old Engine still has
|
||||
no signer mount, so the endpoint remains usable only after the separately
|
||||
accepted Engine artifact. Root/UI transfer is emergency
|
||||
self-hosted diagnostics only, not the user journey or acceptance
|
||||
path. A provider-specific daemon remains forbidden.
|
||||
|
||||
Build the narrow Engine source artifact with:
|
||||
|
||||
```bash
|
||||
node infra/deploy-runner/build-engine-data-product-publish-grant-artifact.mjs \
|
||||
engine-data-product-publish-grant-YYYYMMDD-NNN
|
||||
```
|
||||
|
||||
The builder includes exactly the pinned provider-security catalog, the
|
||||
Publish-grant service, Engine Agent scope/gateway wiring, the existing n8n
|
||||
adapter and the reviewed additive backend runtime overlay. It deliberately
|
||||
excludes base Compose, frontend/dist, runtime data, tests, native credentials,
|
||||
the NDC L2 process and the legacy generic credential-sink route/core. The
|
||||
runner fixes the runtime action to `nodedc-backend` with `--no-deps` and
|
||||
`--pull never`; n8n, nginx app, database services and volumes are not selected.
|
||||
Acceptance requires backend health, the active immutable backend identity and
|
||||
the exact additive mount inventory. Any failure restores the touched source and
|
||||
recreates only the previous verified backend runtime.
|
||||
|
||||
Existing Engine Agents created before Publish-grant support store the original
|
||||
nine scopes as the complete developer profile. They must not require a new
|
||||
agent, setup command or device credential when the profile gains a server-owned
|
||||
capability. Build the compatibility artifact that introduces the durable named
|
||||
`full-developer` profile with:
|
||||
|
||||
```bash
|
||||
node infra/deploy-runner/build-engine-agent-full-grant-migration-artifact.mjs \
|
||||
engine-agent-full-grant-migration-YYYYMMDD-NNN
|
||||
```
|
||||
|
||||
This follow-up slice contains exactly
|
||||
`nodedc-source/server/engineAgents/store.js`. The runner pins its predecessor to
|
||||
the successfully applied Publish generation, requires the installed Publish
|
||||
overlay and active immutable backend, recreates only `nodedc-backend`, and
|
||||
proves the exact candidate SHA, named profile and current expanded runtime
|
||||
scope view. Store schema v1 is migrated atomically to v2 only when a grant
|
||||
contains the complete legacy nine-scope developer bundle. From then on the
|
||||
profile name is the authorization authority and its scope list is derived on
|
||||
every read, so capabilities deliberately added to `full-developer` immediately
|
||||
apply to existing full grants without token or store migrations. Partial grants
|
||||
become `custom` and remain exact; they are never elevated. The artifact does not
|
||||
touch UI, n8n, credentials, agent tokens, workflow graphs, databases or runtime
|
||||
payloads.
|
||||
|
||||
`module-foundry` is an independent, authenticated application component. Its
|
||||
artifact contains source and compose infrastructure only; its live
|
||||
@@ -190,12 +288,17 @@ verified; it does not alter NAS routes, VPN, DNS, or Tailscale.
|
||||
Install or update the root-owned live runner on Synology:
|
||||
|
||||
```bash
|
||||
# First verify that no deploy process is active and state/deploy.lock is absent.
|
||||
sudo install -o root -g root -m 0755 \
|
||||
/volume1/docker/nodedc-deploy/runner-install/nodedc-deploy \
|
||||
/usr/local/sbin/nodedc-deploy
|
||||
sudo /usr/local/sbin/nodedc-deploy verify-install
|
||||
```
|
||||
|
||||
Runner promotion is a standalone admin step, never an app-overlay artifact and
|
||||
never part of a running apply. A Python process already executing the old file
|
||||
keeps the old code in memory; always invoke a fresh verified process afterward.
|
||||
|
||||
Normal service deploys must still use explicit artifacts:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -202,7 +202,13 @@ TASKER_SYNC_SOURCE=1 ./infra/synology/deploy-current.sh
|
||||
|
||||
Если emergency-fix был сделан прямо на Synology в этих env-файлах, перенести sanitized-значение в `.env.synology.example`/docs, а секрет оставить только в live env.
|
||||
|
||||
### Gelios: сбор всех units доверенного подключения
|
||||
### Gelios: frozen legacy compatibility contour
|
||||
|
||||
`gelios-postgres` и `gelios-gateway` — уже существующий self-hosted контур с
|
||||
собственным persistent Timescale volume. Он остаётся полностью воспроизводимым
|
||||
в source/deploy, но не развивается и не используется как шаблон для новых
|
||||
провайдеров. Его удаление или миграция требуют отдельного подтверждённого плана;
|
||||
обычный Platform/EDP deploy не удаляет volume и не изменяет старый workflow.
|
||||
|
||||
`GELIOS_UNIT_SCOPE=all` означает **все текущие и будущие units только одной уже
|
||||
настроенной пары `GELIOS_TENANT_ID` + `GELIOS_CONNECTION_ID`**. Это не wildcard
|
||||
@@ -210,17 +216,71 @@ TASKER_SYNC_SOURCE=1 ./infra/synology/deploy-current.sh
|
||||
Пропавший из очередного ответа unit не удаляется: его stable provider ID и
|
||||
`last_seen_at` сохраняются; видимость на карте — отдельная логика витрины.
|
||||
|
||||
Перед каноническим `nodedc-deploy apply` включить политику на Synology (скрипт
|
||||
создаёт backup и не выводит секреты):
|
||||
Перед узким legacy apply включить политику на Synology (скрипт создаёт backup и
|
||||
не выводит секреты):
|
||||
|
||||
```bash
|
||||
sudo bash /volume1/docker/nodedc-deploy/inbox/prepare-gelios-all-units-env.sh
|
||||
```
|
||||
|
||||
Затем применить узкий Platform-артефакт, собранный с `--gateway-only`, через
|
||||
`nodedc-deploy`. В его plan должны быть только `gelios-postgres` и
|
||||
`gelios-gateway`; общий `docker-compose` в такой архив не входит. После apply
|
||||
Gateway начинает принимать весь состав units этого подключения.
|
||||
В plan такого Platform-артефакта должны быть только `gelios-postgres` и
|
||||
`gelios-gateway`; общий compose в узкий архив не входит.
|
||||
|
||||
## EDP publish grant: platform-owned credential
|
||||
|
||||
`NDC Data Product Writer API` — историческое имя native credential type для
|
||||
внутреннего scoped EDP publish grant. Это не Gelios access/refresh token и не
|
||||
право записи в Gelios.
|
||||
|
||||
Целевой путь полностью служебный: control plane NDC по разрешённому connection
|
||||
profile генерирует capability внутри native NDC L2 Credentials, передаёт EDP
|
||||
только digest для scoped binding и возвращает MCP только opaque compatible
|
||||
reference/status.
|
||||
Пользователь не читает, не копирует и не вводит этот внутренний секрет.
|
||||
|
||||
EDP уже имеет localhost-only digest-only managed endpoint. Managed endpoint и
|
||||
legacy plaintext provisioning имеют раздельные флаги и по умолчанию выключены.
|
||||
Runner-owned provisioner bearer относится только к legacy plaintext routes и
|
||||
на managed ensure/revoke намеренно не действует. Managed caller contract —
|
||||
Ed25519-signed Engine service request с exact audience, method, request target,
|
||||
raw-body SHA-256, timestamp и одноразовым nonce; EDP хранит только public key и
|
||||
fail-closed replay cache. Ни bearer, ни signing private key нельзя открывать
|
||||
workflow, MCP или переиспользовать как shared credential. В source-кандидате
|
||||
Engine добавлен отдельный server-derived plan/apply для exact пары
|
||||
`ndcDataProductWriterApi` + custom Publish node; он не расширяет generic HTTP
|
||||
safe-ref policy и не принимает provider/scope/credential identity, capability,
|
||||
generation или service URL от MCP. До отдельного Engine deploy и runtime proof
|
||||
текущий deployed MCP этого контракта не имеет. Поэтому отсутствие
|
||||
совместимого reference — платформенный runtime gap, а не действие пользователя.
|
||||
Ручной перенос capability из отдельно включаемого legacy endpoint через root/UI допустим только как аварийная
|
||||
диагностика self-hosted контура; он не является acceptance-путём и не должен
|
||||
закрепляться в пользовательской автоматизации.
|
||||
|
||||
Compose монтирует read-only trust directory
|
||||
`/volume1/docker/nodedc-platform/trust/engine-managed-provisioner` в EDP; в нём
|
||||
ожидается один regular, non-symlink файл `public-key.pem` с Ed25519 SPKI public
|
||||
key. Файл не должен быть group/world-writable и должен читаться runtime UID
|
||||
`11006`. Private key в этот каталог, Platform artifact, `.env` или EDP
|
||||
контейнер не попадает. Canonical deploy runner теперь атомарно создаёт или
|
||||
проверяет matching Ed25519 pair перед relevant Engine/EDP Compose apply: private
|
||||
key остаётся `root:root 0400`, public trust — `root:11006 0440`; public-only
|
||||
crash state, mismatch, symlink и неверный тип ключа отклоняются до запуска.
|
||||
`EXTERNAL_DATA_PLANE_MANAGED_PROVISIONING_ENABLED` остаётся `false` на staging.
|
||||
В отдельно подтверждённом activation window его переводят в `true`
|
||||
непосредственно перед Platform EDP artifact; runner принимает deploy только
|
||||
если `/healthz` явно вернул managed status `enabled`. Старый Engine в этот
|
||||
момент ещё не имеет signer mount, поэтому usable caller появляется лишь после
|
||||
следующего отдельно принятого Engine artifact.
|
||||
EDP application artifact пересобирает и force-recreate только
|
||||
`external-data-plane`. Уже работающий `external-data-plane-postgres` и его
|
||||
Timescale volume runner не выбирает и не перезапускает; healthy database —
|
||||
обязательная deploy prerequisite.
|
||||
Canonical service/key/audience заданы в `.env.synology.example`; wire headers и
|
||||
canonical signing payload описаны в `packages/external-provider-contract/README.md`.
|
||||
|
||||
До появления opaque compatible reference и успешного manual publish proof
|
||||
Schedule Trigger не включать. Frozen legacy workflow и его credentials этот
|
||||
процесс не изменяет.
|
||||
|
||||
## AI Hub relay-only deploy
|
||||
|
||||
|
||||
Reference in New Issue
Block a user