diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 533faf03..bf053791 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -7,6 +7,34 @@ on: workflow_dispatch: jobs: + tnt_core_sync: + name: tnt-core sync + runs-on: ubuntu-latest + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.11.0 + with: + access_token: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/checkout@v3 + + - name: Checkout tnt-core main + uses: actions/checkout@v3 + with: + repository: tangle-network/tnt-core + ref: main + path: tnt-core + + - name: Use Node.js 22.x + uses: actions/setup-node@v4 + with: + node-version: 22.x + + - name: Validate docs against tnt-core + run: node ./scripts/check-tnt-core-sync.mjs + env: + TNT_CORE_DIR: ${{ github.workspace }}/tnt-core + lint: name: lint runs-on: ubuntu-latest @@ -81,7 +109,17 @@ jobs: - name: Link Checker uses: lycheeverse/lychee-action@v1.9.0 with: - args: --verbose --no-progress './**/*.md' './**/*.html' './**/*.mdx' + token: ${{ secrets.GITHUB_TOKEN }} + args: >- + --verbose + --no-progress + --max-concurrency 16 + --max-retries 5 + --retry-wait-time 2 + --accept '100..=103,200..=299,403,429' + './**/*.md' + './**/*.html' + './**/*.mdx' fail: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/package.json b/package.json index bc486614..f2c19ff8 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build:sitemap": "next-sitemap --config next-sitemap.config.js", "build:pagefind": "pagefind --site .next/server/pages --output-path dist/_pagefind", "export": "next export", + "check:tnt-core-sync": "node ./scripts/check-tnt-core-sync.mjs", "lint": "next lint && yarn format", "schema": "turbo-gen ./public/schema.json", "format": "prettier --write \"{components,pages}/**/*.{mdx,ts,js,jsx,tsx,json}\" ", diff --git a/pages/developers/api/reference/ITangleServices.mdx b/pages/developers/api/reference/ITangleServices.mdx index 7e62887d..f7d5171a 100644 --- a/pages/developers/api/reference/ITangleServices.mdx +++ b/pages/developers/api/reference/ITangleServices.mdx @@ -16,7 +16,7 @@ Service lifecycle management interface #### requestService ```solidity -function requestService(uint64 blueprintId, address[] operators, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount) external payable returns (uint64 requestId) +function requestService(uint64 blueprintId, address[] operators, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount, enum Types.ConfidentialityPolicy confidentiality) external payable returns (uint64 requestId) ``` Request a new service @@ -24,7 +24,7 @@ Request a new service #### requestServiceWithExposure ```solidity -function requestServiceWithExposure(uint64 blueprintId, address[] operators, uint16[] exposureBps, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount) external payable returns (uint64 requestId) +function requestServiceWithExposure(uint64 blueprintId, address[] operators, uint16[] exposureBps, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount, enum Types.ConfidentialityPolicy confidentiality) external payable returns (uint64 requestId) ``` Request a service with explicit exposure commitments @@ -32,13 +32,21 @@ Request a service with explicit exposure commitments #### requestServiceWithSecurity ```solidity -function requestServiceWithSecurity(uint64 blueprintId, address[] operators, struct Types.AssetSecurityRequirement[] securityRequirements, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount) external payable returns (uint64 requestId) +function requestServiceWithSecurity(uint64 blueprintId, address[] operators, struct Types.AssetSecurityRequirement[] securityRequirements, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount, enum Types.ConfidentialityPolicy confidentiality) external payable returns (uint64 requestId) ``` Request a service with multi-asset security requirements _Each operator must provide security commitments matching these requirements when approving_ +#### getServiceRequestResourceRequirements + +```solidity +function getServiceRequestResourceRequirements(uint64 requestId) external view returns (struct Types.ResourceCommitment[]) +``` + +Get resource requirements for a service request + #### approveService ```solidity @@ -57,6 +65,22 @@ Approve a service request with multi-asset security commitments _Commitments must match the security requirements specified in the request_ +#### approveServiceWithBls + +```solidity +function approveServiceWithBls(uint64 requestId, uint8 stakingPercent, uint256[4] blsPubkey) external +``` + +Approve a service request with BLS public key for aggregated signature verification + +#### approveServiceWithCommitmentsAndBls + +```solidity +function approveServiceWithCommitmentsAndBls(uint64 requestId, struct Types.AssetSecurityCommitment[] commitments, uint256[4] blsPubkey) external +``` + +Approve a service request with both security commitments and BLS public key + #### rejectService ```solidity @@ -101,6 +125,14 @@ function terminateService(uint64 serviceId) external Terminate a service (as owner) +#### terminateServiceForNonPayment + +```solidity +function terminateServiceForNonPayment(uint64 serviceId) external +``` + +Permissionlessly terminate an unpaid subscription after grace period + #### addPermittedCaller ```solidity @@ -361,13 +393,13 @@ Get current service count #### ServiceRequested ```solidity -event ServiceRequested(uint64 requestId, uint64 blueprintId, address requester) +event ServiceRequested(uint64 requestId, uint64 blueprintId, address requester, enum Types.ConfidentialityPolicy confidentiality) ``` #### ServiceRequestedWithSecurity ```solidity -event ServiceRequestedWithSecurity(uint64 requestId, uint64 blueprintId, address requester) +event ServiceRequestedWithSecurity(uint64 requestId, uint64 blueprintId, address requester, enum Types.ConfidentialityPolicy confidentiality) ``` #### ServiceApproved @@ -385,7 +417,7 @@ event ServiceRejected(uint64 requestId, address operator) #### ServiceActivated ```solidity -event ServiceActivated(uint64 serviceId, uint64 requestId, uint64 blueprintId) +event ServiceActivated(uint64 serviceId, uint64 requestId, uint64 blueprintId, enum Types.ConfidentialityPolicy confidentiality) ``` #### ServiceTerminated @@ -394,6 +426,12 @@ event ServiceActivated(uint64 serviceId, uint64 requestId, uint64 blueprintId) event ServiceTerminated(uint64 serviceId) ``` +#### ServiceTerminatedForNonPayment + +```solidity +event ServiceTerminatedForNonPayment(uint64 serviceId, address triggeredBy, uint64 dueAt, uint64 graceEndsAt, uint256 requiredAmount, uint256 escrowBalance) +``` + #### OperatorJoinedService ```solidity diff --git a/pages/developers/api/reference/generated/ITangleServices.mdx b/pages/developers/api/reference/generated/ITangleServices.mdx index 7e62887d..f7d5171a 100644 --- a/pages/developers/api/reference/generated/ITangleServices.mdx +++ b/pages/developers/api/reference/generated/ITangleServices.mdx @@ -16,7 +16,7 @@ Service lifecycle management interface #### requestService ```solidity -function requestService(uint64 blueprintId, address[] operators, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount) external payable returns (uint64 requestId) +function requestService(uint64 blueprintId, address[] operators, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount, enum Types.ConfidentialityPolicy confidentiality) external payable returns (uint64 requestId) ``` Request a new service @@ -24,7 +24,7 @@ Request a new service #### requestServiceWithExposure ```solidity -function requestServiceWithExposure(uint64 blueprintId, address[] operators, uint16[] exposureBps, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount) external payable returns (uint64 requestId) +function requestServiceWithExposure(uint64 blueprintId, address[] operators, uint16[] exposureBps, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount, enum Types.ConfidentialityPolicy confidentiality) external payable returns (uint64 requestId) ``` Request a service with explicit exposure commitments @@ -32,13 +32,21 @@ Request a service with explicit exposure commitments #### requestServiceWithSecurity ```solidity -function requestServiceWithSecurity(uint64 blueprintId, address[] operators, struct Types.AssetSecurityRequirement[] securityRequirements, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount) external payable returns (uint64 requestId) +function requestServiceWithSecurity(uint64 blueprintId, address[] operators, struct Types.AssetSecurityRequirement[] securityRequirements, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount, enum Types.ConfidentialityPolicy confidentiality) external payable returns (uint64 requestId) ``` Request a service with multi-asset security requirements _Each operator must provide security commitments matching these requirements when approving_ +#### getServiceRequestResourceRequirements + +```solidity +function getServiceRequestResourceRequirements(uint64 requestId) external view returns (struct Types.ResourceCommitment[]) +``` + +Get resource requirements for a service request + #### approveService ```solidity @@ -57,6 +65,22 @@ Approve a service request with multi-asset security commitments _Commitments must match the security requirements specified in the request_ +#### approveServiceWithBls + +```solidity +function approveServiceWithBls(uint64 requestId, uint8 stakingPercent, uint256[4] blsPubkey) external +``` + +Approve a service request with BLS public key for aggregated signature verification + +#### approveServiceWithCommitmentsAndBls + +```solidity +function approveServiceWithCommitmentsAndBls(uint64 requestId, struct Types.AssetSecurityCommitment[] commitments, uint256[4] blsPubkey) external +``` + +Approve a service request with both security commitments and BLS public key + #### rejectService ```solidity @@ -101,6 +125,14 @@ function terminateService(uint64 serviceId) external Terminate a service (as owner) +#### terminateServiceForNonPayment + +```solidity +function terminateServiceForNonPayment(uint64 serviceId) external +``` + +Permissionlessly terminate an unpaid subscription after grace period + #### addPermittedCaller ```solidity @@ -361,13 +393,13 @@ Get current service count #### ServiceRequested ```solidity -event ServiceRequested(uint64 requestId, uint64 blueprintId, address requester) +event ServiceRequested(uint64 requestId, uint64 blueprintId, address requester, enum Types.ConfidentialityPolicy confidentiality) ``` #### ServiceRequestedWithSecurity ```solidity -event ServiceRequestedWithSecurity(uint64 requestId, uint64 blueprintId, address requester) +event ServiceRequestedWithSecurity(uint64 requestId, uint64 blueprintId, address requester, enum Types.ConfidentialityPolicy confidentiality) ``` #### ServiceApproved @@ -385,7 +417,7 @@ event ServiceRejected(uint64 requestId, address operator) #### ServiceActivated ```solidity -event ServiceActivated(uint64 serviceId, uint64 requestId, uint64 blueprintId) +event ServiceActivated(uint64 serviceId, uint64 requestId, uint64 blueprintId, enum Types.ConfidentialityPolicy confidentiality) ``` #### ServiceTerminated @@ -394,6 +426,12 @@ event ServiceActivated(uint64 serviceId, uint64 requestId, uint64 blueprintId) event ServiceTerminated(uint64 serviceId) ``` +#### ServiceTerminatedForNonPayment + +```solidity +event ServiceTerminatedForNonPayment(uint64 serviceId, address triggeredBy, uint64 dueAt, uint64 graceEndsAt, uint256 requiredAmount, uint256 escrowBalance) +``` + #### OperatorJoinedService ```solidity diff --git a/pages/developers/blueprints/_meta.ts b/pages/developers/blueprints/_meta.ts index f19f67ca..d4fc6807 100644 --- a/pages/developers/blueprints/_meta.ts +++ b/pages/developers/blueprints/_meta.ts @@ -2,6 +2,7 @@ import { Meta } from "nextra"; const meta: Meta = { introduction: "Introduction", + "execution-confidentiality": "Execution Confidentiality", "use-cases": "Use Cases", "service-lifecycle": "Service Lifecycle", "pricing-and-payments": "Pricing & Payments", diff --git a/pages/developers/blueprints/execution-confidentiality.mdx b/pages/developers/blueprints/execution-confidentiality.mdx new file mode 100644 index 00000000..27d50743 --- /dev/null +++ b/pages/developers/blueprints/execution-confidentiality.mdx @@ -0,0 +1,113 @@ +--- +title: Execution Confidentiality +description: How blueprint developers declare TEE intent, how operators enforce it, and how customers request confidentiality on-chain. +--- + +# Execution Confidentiality + +Tangle models trusted execution as an execution policy, not as a separate source type. A blueprint still publishes +normal artifact sources such as containers or native binaries. Confidentiality intent is declared in blueprint metadata +and, at the protocol layer, can also be requested by the customer when a service is created. + +## Confidentiality Policies + +Tangle uses four confidentiality modes: + +- `any`: standard execution and TEE execution are both acceptable. +- `tee_preferred`: prefer TEE placement when the operator can satisfy it, but allow standard execution. +- `tee_required`: require TEE placement and fail closed if it cannot be satisfied. +- `standard_required`: require non-TEE execution. + +## How Developers Declare It + +When you register a blueprint through a definition manifest, set the execution policy under +`metadata.execution_profile.confidentiality`: + +```json +{ + "metadata_uri": "ipfs://your-blueprint-metadata", + "metadata": { + "name": "confidential-prover", + "execution_profile": { + "confidentiality": "tee_required" + } + }, + "sources": [ + { + "kind": "container", + "registry": "ghcr.io", + "image": "acme/confidential-prover", + "tag": "1.2.0" + } + ] +} +``` + +If you prefer TOML: + +```toml +metadata_uri = "ipfs://your-blueprint-metadata" + +[metadata] +name = "confidential-prover" + +[metadata.execution_profile] +confidentiality = "tee_required" +``` + +The CLI injects this into on-chain `profilingData` as structured JSON metadata. + +## What The Manager Does + +On the Tangle manager path, the confidentiality policy changes source selection and runtime behavior: + +- Only container sources are eligible for TEE placement today. +- `tee_required` filters launch candidates down to container sources and fails if none exist. +- `tee_required` also fails closed if the operator does not have the required TEE runtime prerequisites. +- `tee_preferred` prioritizes container execution and uses Kata when available, but can still fall back. +- `standard_required` keeps the service on the standard, non-TEE path. + +For local container execution, `tee_required` currently means the operator must have Kubernetes configured with the +`kata` runtime class. For remote deployments, the operator must configure a TEE-capable provider and attestation policy. + +## Source Design Guidance + +Do not create a separate "TEE source" entry in your blueprint manifest. Keep sources focused on how the artifact is +fetched and executed: + +- `Container` tells operators where to fetch the image. +- `Native` tells operators where to fetch the binary. +- `Wasm` tells operators which WASM runtime to use. + +Confidentiality is a deployment policy layered on top of those sources. + +In practice, if you want a blueprint to run in a TEE on Tangle today, publish a container source and declare either +`tee_preferred` or `tee_required`. + +## Customer Request Semantics + +At the protocol layer, service requests and service RFQ quotes now carry a confidentiality intent. That lets a customer +ask for standard execution, preferred TEE execution, or required TEE execution as part of the service agreement. + +Important consequences: + +- Request-and-approve flows include confidentiality on the service request. +- RFQ service creation includes confidentiality inside `QuoteDetails`. +- All quotes in a single RFQ service creation or extension must agree on confidentiality. +- Service extensions preserve the active service's confidentiality mode. If you need to switch modes, create a new + service. + +## Tooling Status + +Blueprint definition manifests already support `metadata.execution_profile.confidentiality`. + +The protocol API also supports customer-selected confidentiality in `ITangleServices`, but high-level helper surfaces may +lag behind the newest contract fields. If your installed SDK or CLI does not expose the latest confidentiality argument +yet, use the current contract bindings or raw interface calls for service creation. + +## Related Docs + +- [Deploying Blueprints](/developers/deployment/introduction) +- [Blueprint Sources](/developers/deployment/sources/introduction) +- [Service Lifecycle](/developers/blueprints/service-lifecycle) +- [Blueprint Manager Setup](/operators/manager/setup) diff --git a/pages/developers/blueprints/introduction.mdx b/pages/developers/blueprints/introduction.mdx index 2fa9a3b8..3609f0ee 100644 --- a/pages/developers/blueprints/introduction.mdx +++ b/pages/developers/blueprints/introduction.mdx @@ -30,7 +30,7 @@ Customers discover Blueprints, create Services, and pay for execution. Operators earning fees and TNT incentives defined by the core protocol contracts in `tnt-core`. A Blueprint Service is a reusable computational service. Each Service instance can select a different operator set, -security configuration, and payment token while sharing the same underlying blueprint logic. +security configuration, payment token, and execution confidentiality while sharing the same underlying blueprint logic. A Tangle Blueprint is defined by: @@ -39,6 +39,8 @@ A Tangle Blueprint is defined by: - **Executable artifacts** (native binary, container image, or WASM) for operators to run. Blueprints specify their runtime preferences so operators can execute services natively, in containers, or inside a VM. +They can also declare execution confidentiality policy in metadata. See +[/developers/blueprints/execution-confidentiality](/developers/blueprints/execution-confidentiality). ## Detailed Interactions @@ -56,6 +58,8 @@ schemas operators should run. The on-chain manager contract handles: Blueprints let developers define monetizable services (MPC, ZK proving, AI infrastructure, oracles) with on-chain verification and off-chain execution handled by operators running the Blueprint Manager. +Developers can also declare whether a service may run in a TEE, should prefer TEE placement, or must run in a TEE. + ### Customers Customers discover blueprints, configure services, and select operators based on requirements (security, resources, price, @@ -65,13 +69,17 @@ To initialize a Service, a customer typically: 1. Chooses an operator set and any service parameters required by the blueprint. 2. Provides metadata required by the Service instance. -3. Funds the service fee required by the blueprint manager contract. +3. Selects the desired execution confidentiality when the service flow supports it. +4. Funds the service fee required by the blueprint manager contract. ### Operators Operators register for blueprints, accept service assignments, and run the service artifacts through the Blueprint Manager. They earn an operator share of service payments (claimable from the `Tangle` contract) plus TNT incentives. +Execution confidentiality changes how operators satisfy those assignments. For example, a `tee_required` service must fail +closed if the operator cannot satisfy the TEE runtime requirements. + ### Payments and Incentives Service payments are split by the core protocol contracts in `tnt-core`: diff --git a/pages/developers/blueprints/manager.mdx b/pages/developers/blueprints/manager.mdx index a77b03be..953e4fbd 100644 --- a/pages/developers/blueprints/manager.mdx +++ b/pages/developers/blueprints/manager.mdx @@ -14,7 +14,7 @@ functions as follows: 2. Operators download the Blueprint's artifacts and metadata after registering. The Blueprint Manager watches chain events and keeps the operator runtime in sync. 3. Operators execute Blueprint services when they are assigned. The Blueprint Manager runs artifacts natively, in a - container, or inside a VM based on the blueprint definition. + container, or inside a VM based on the blueprint definition and confidentiality policy. ### Blueprint and Service Instance Lifecycle @@ -26,6 +26,9 @@ Blueprints interact with the Tangle Network in several key ways: 2. Customers instantiate a Service, which represents a single configured service instance. 3. Services end once they reach their time-to-live (TTL) or run out of funds to pay operators. +When confidentiality is declared or requested, the manager uses that policy to decide whether standard execution is +acceptable, whether TEE placement should be preferred, or whether it must fail closed. + For renewal, migration, and expiry edge cases, see: - `/developers/blueprints/service-lifecycle` @@ -35,3 +38,6 @@ Blueprints provide a useful abstraction, allowing developers to create reusable Blueprints and Services are managed by the Tangle v2 contracts in `tnt-core`, including the core `Tangle` contract and the `BlueprintServiceManager` stack. Staking and operator registration live in these contracts, and the Blueprint Manager watches their events to decide what to run. + +See [/developers/blueprints/execution-confidentiality](/developers/blueprints/execution-confidentiality) for the exact +TEE and confidentiality behavior. diff --git a/pages/developers/blueprints/pricing-and-payments.mdx b/pages/developers/blueprints/pricing-and-payments.mdx index 4ad38eac..35d46263 100644 --- a/pages/developers/blueprints/pricing-and-payments.mdx +++ b/pages/developers/blueprints/pricing-and-payments.mdx @@ -46,6 +46,8 @@ Flows that typically require custom code today: - Per-job RFQ submission (`submitJobFromQuote`): you need to request signed quotes off-chain, then submit the job with the quotes. - Service RFQ creation (`createServiceFromQuotes` / `extendServiceFromQuotes`): you need to request signed service quotes off-chain, then create or extend the service using those quotes. +- Service confidentiality selection: the protocol now carries confidentiality intent on service requests and RFQ service + quotes, so advanced integrations may need direct contract bindings until all helper layers expose the new field. For Rust clients, `TangleClient` supports RFQ job submission: @@ -101,10 +103,13 @@ operator-run gateway. See: Service RFQ lets a user create a service instantly using operator quotes: -1. User requests service quotes from operators for `(blueprintId, ttlBlocks, security requirements)`. -2. Operators sign EIP-712 `QuoteDetails { blueprintId, ttlBlocks, totalCost, timestamp, expiry, ... }`. +1. User requests service quotes from operators for `(blueprintId, ttlBlocks, confidentiality, security requirements)`. +2. Operators sign EIP-712 `QuoteDetails { blueprintId, ttlBlocks, totalCost, timestamp, expiry, confidentiality, ... }`. 3. User calls `createServiceFromQuotes(...)` (or `extendServiceFromQuotes(...)`) with quotes and payment. +All quotes for a single RFQ service creation or extension must agree on confidentiality. Changing confidentiality mode is +treated as a new service agreement, not an in-place extension. + This is separate from the request and approval service lifecycle flow that the CLI exposes under `cargo tangle blueprint service`. For renewal and expiry semantics (including limitations of `extendServiceFromQuotes` and migration recommendations), see: diff --git a/pages/developers/blueprints/service-lifecycle.mdx b/pages/developers/blueprints/service-lifecycle.mdx index 2d005d8b..cb7f5cb6 100644 --- a/pages/developers/blueprints/service-lifecycle.mdx +++ b/pages/developers/blueprints/service-lifecycle.mdx @@ -32,6 +32,10 @@ There are two high-level creation flows: The CLI primarily covers the request and approve flow. RFQ flows often require custom client code today. +Both flows can now carry execution confidentiality intent at the protocol layer. That means service creation can bind not +just operator set and payment terms, but also whether the service should run in standard execution, prefer TEE, or +require TEE. + ## Extending A Service (Renewal) The protocol supports renewal for RFQ-created services via: @@ -45,6 +49,8 @@ Key properties to design around: - Only the **service owner** can extend a service. - Extension applies to services that have a TTL (`ttl != 0`). - Quotes must come from the **current operators of the service**. Extension does not change the operator set. +- Extensions preserve the active service's confidentiality mode. If you need a different confidentiality policy, create a + new service. - Payment is provided with the transaction (for example, via `msg.value` depending on the quote format and payment asset). - Extension can be executed even after the service has expired, as long as it is still active. The service can resume job acceptance after TTL is increased. diff --git a/pages/developers/cli/tangle.mdx b/pages/developers/cli/tangle.mdx index 7030d667..1e1c2b25 100644 --- a/pages/developers/cli/tangle.mdx +++ b/pages/developers/cli/tangle.mdx @@ -37,6 +37,10 @@ cargo tangle blueprint preregister \ --settings-file ./settings.env ``` +Blueprint definition manifests can include `metadata.execution_profile.confidentiality` to declare `any`, +`tee_preferred`, `tee_required`, or `standard_required`. See +[/developers/blueprints/execution-confidentiality](/developers/blueprints/execution-confidentiality). + ## Register as an Operator for a Blueprint Register your operator against the on-chain protocol contracts: @@ -69,6 +73,10 @@ cargo tangle blueprint service --help cargo tangle blueprint service request --help ``` +The protocol now supports confidentiality intent on service requests and RFQ service quotes. Depending on the SDK/CLI +version you are running, the newest confidentiality argument may appear first in the raw contract interfaces before every +high-level helper command exposes it. + Example (operator approval flow): ```bash diff --git a/pages/developers/deployment/introduction.mdx b/pages/developers/deployment/introduction.mdx index a46935e3..54c99c71 100644 --- a/pages/developers/deployment/introduction.mdx +++ b/pages/developers/deployment/introduction.mdx @@ -2,6 +2,9 @@ In order for a blueprint to be instance-able, it'll need to be deployed and have one or more sources defined. +If your blueprint has confidentiality requirements, also declare an execution policy in blueprint metadata. TEE is not a +separate source type. See [Execution Confidentiality](/developers/blueprints/execution-confidentiality). + ## Defining Sources Before deploying, you must specify the sources from which to fetch the blueprint binaries. @@ -25,6 +28,6 @@ export EVM_SIGNER="0xcb6df9de1efca7a3998a8ead4e02159d5fa99c3e0d4fd6432667390bb47 cargo tangle blueprint deploy tangle --devnet ``` -See [deploy command reference](/developers/cli/tangle#deploying-a-blueprint) for all options. +See [Tangle CLI reference](/developers/cli/tangle) for the current command flow and options. [cargo-tangle]: https://github.com/tangle-network/blueprint/tree/main/cli diff --git a/pages/developers/deployment/sources/container.mdx b/pages/developers/deployment/sources/container.mdx index 021a6fbd..6541872a 100644 --- a/pages/developers/deployment/sources/container.mdx +++ b/pages/developers/deployment/sources/container.mdx @@ -3,6 +3,10 @@ The `Container` source is used for blueprints that are intended to be built as container images and published to image registries, such as `docker.io`. +Container sources are also the only TEE-eligible artifact source on the current Tangle manager path. If you want to +allow or require TEE execution, keep using `Container` and declare the confidentiality policy in blueprint metadata. See +[Execution Confidentiality](/developers/blueprints/execution-confidentiality). + ## Requirements The requirements for running containerized blueprints are available [here](/operators/manager/requirements#container-sources) diff --git a/pages/developers/deployment/sources/introduction.mdx b/pages/developers/deployment/sources/introduction.mdx index d09d7ebe..d64ecda6 100644 --- a/pages/developers/deployment/sources/introduction.mdx +++ b/pages/developers/deployment/sources/introduction.mdx @@ -2,6 +2,10 @@ Blueprints can be built and distributed in multiple formats (visible on the sidebar). +Sources describe how operators fetch and execute your artifact. They do not describe confidentiality policy. If your +blueprint should run in a TEE, declare that separately in `metadata.execution_profile.confidentiality`. See +[Execution Confidentiality](/developers/blueprints/execution-confidentiality). + A blueprint can define many sources of different types in the manifest of its binary crate: ```toml @@ -20,3 +24,6 @@ sources = [ The above example has two container sources, which allows an operator to attempt a pull from different sources in the event that one of the registries is unreachable. Additionally, it has a native source which can act as a fallback for operators that either cannot or prefer not to support running containerized blueprints. + +Today, only container sources are eligible for TEE placement on the Tangle manager path. That still does not make TEE a +new source type; it remains a deployment policy layered on top of container execution. diff --git a/pages/developers/deployment/sources/testing.mdx b/pages/developers/deployment/sources/testing.mdx index 6e805890..0277ae64 100644 --- a/pages/developers/deployment/sources/testing.mdx +++ b/pages/developers/deployment/sources/testing.mdx @@ -1,7 +1,7 @@ # Testing Source The `Testing` source is a special, automatically generated source that was historically used by the [Blueprint Manager] -during integration tests. It has since been replaced with the [test harnesses](/developers/testing/introduction). +during integration tests. It has since been replaced with the [test harnesses](/developers/testing-with-tangle). ## Format diff --git a/pages/operators/introduction.mdx b/pages/operators/introduction.mdx index 15e06649..8d223725 100644 --- a/pages/operators/introduction.mdx +++ b/pages/operators/introduction.mdx @@ -28,6 +28,9 @@ Operators select how to isolate workloads: See [Requirements](/operators/manager/requirements) for setup details. +If you want to serve TEE-aware workloads, continue with +[Confidential Compute](/operators/manager/confidential-compute). + ## Earning and Risks Operators earn from: diff --git a/pages/operators/manager/_meta.ts b/pages/operators/manager/_meta.ts index 0253d06d..2c65ee28 100644 --- a/pages/operators/manager/_meta.ts +++ b/pages/operators/manager/_meta.ts @@ -4,6 +4,7 @@ const meta: Meta = { introduction: "Introduction", requirements: "Requirements", setup: "Setup", + "confidential-compute": "Confidential Compute", sizing: "Sizing", security: "Sandboxing and Security", }; diff --git a/pages/operators/manager/confidential-compute.mdx b/pages/operators/manager/confidential-compute.mdx new file mode 100644 index 00000000..0748c88e --- /dev/null +++ b/pages/operators/manager/confidential-compute.mdx @@ -0,0 +1,89 @@ +# Confidential Compute + +SDK source (GitHub): https://github.com/tangle-network/blueprint/tree/main/crates/manager + +This page covers the operator requirements for running services that prefer or require TEE execution. + +## Two TEE Paths + +Operators can satisfy confidentiality requirements in two different ways today: + +- Local container TEE path: run container sources on Kubernetes with the `kata` runtime class. +- Remote TEE path: provision a confidential-compute VM through a supported cloud provider and run the blueprint there. + +The blueprint manager treats TEE as a deployment policy. It does not require a separate "TEE source" entry in the +blueprint manifest. + +## Local Container TEE Path + +For container sources on the Tangle manager path: + +- `tee_required` fails closed if no container source exists. +- `tee_required` fails closed if Kubernetes does not expose the `kata` runtime class. +- `tee_preferred` uses Kata when available, but can still fall back to standard execution. + +At minimum, operators need: + +- Kubernetes +- Docker or a compatible container runtime +- Kata Containers installed and exposed as the `kata` runtime class + +## Remote TEE Path + +Remote confidential-compute deployments currently require a TEE-capable provider: + +- AWS +- GCP +- Azure + +When TEE is required, the manager must not silently fall back to non-TEE providers. + +## Preflight Workflow + +The fastest way to validate remote TEE readiness is: + +```bash +cargo tangle cloud configure aws --region us-east-1 --set-default +cargo tangle cloud preflight --tee-required --bootstrap-env +``` + +That checks provider configuration, cloud credentials, TEE capability, and attestation policy requirements before you run +the manager. + +## Required Environment + +For remote TEE deployments, operators should expect to configure: + +```bash +export BLUEPRINT_REMOTE_TEE_REQUIRED=true +export BLUEPRINT_REMOTE_TEE_ATTESTATION_POLICY=cryptographic +export BLUEPRINT_REMOTE_TEE_ATTESTATION_VERIFY_CMD=/usr/local/bin/verify-tee-attestation +export TEE_BACKEND=aws-nitro +``` + +`BLUEPRINT_REMOTE_TEE_ATTESTATION_POLICY` supports: + +- `cryptographic`: requires `BLUEPRINT_REMOTE_TEE_ATTESTATION_VERIFY_CMD` to be present and executable. +- `structural`: checks structural provider readiness without an external verifier command. + +If GCP is the selected provider, the preflight path also expects: + +```bash +export BLUEPRINT_ALLOWED_SSH_CIDRS=10.0.0.0/8 +export BLUEPRINT_ALLOWED_QOS_CIDRS=10.0.0.0/8 +``` + +## What Operators Should Expect + +- `tee_required` prevents non-TEE fallback. +- The manager injects `TEE_REQUIRED=true` and `TEE_BACKEND` into remote deployments when TEE is required. +- Cryptographic attestation policy fails the deployment if attestation verification fails. +- `tee_preferred` is softer: the operator can still serve the workload without hard failure if the blueprint policy allows + fallback. + +## Related Docs + +- [Requirements](/operators/manager/requirements) +- [Setup](/operators/manager/setup) +- [Sandboxing and Security](/operators/manager/security) +- [Execution Confidentiality](/developers/blueprints/execution-confidentiality) diff --git a/pages/operators/manager/introduction.mdx b/pages/operators/manager/introduction.mdx index c59b918a..6cd3d61a 100644 --- a/pages/operators/manager/introduction.mdx +++ b/pages/operators/manager/introduction.mdx @@ -21,4 +21,5 @@ For operator setup and runtime choices, continue with: - [Setup](/operators/manager/setup) - [Runtime Requirements](/operators/manager/requirements) +- [Confidential Compute](/operators/manager/confidential-compute) - [Sizing](/operators/manager/sizing) diff --git a/pages/operators/manager/requirements.mdx b/pages/operators/manager/requirements.mdx index 7bea3786..8c133797 100644 --- a/pages/operators/manager/requirements.mdx +++ b/pages/operators/manager/requirements.mdx @@ -37,7 +37,15 @@ The requirements for running blueprints with [Container Sources](/developers/dep - [Kubernetes] - [Docker] -- The [Kata Containers] runtime + +For standard container execution, Kubernetes and Docker are enough. + +For confidentiality-aware execution: + +- `tee_required` needs the [Kata Containers] runtime exposed as the Kubernetes `kata` runtime class. +- `tee_preferred` should also use Kata when available, but may fall back if the blueprint policy permits it. + +See [Confidential Compute](/operators/manager/confidential-compute) for the full operator flow. ## WASM Sources (WIP) diff --git a/pages/operators/manager/security.mdx b/pages/operators/manager/security.mdx index 8e9362f5..ee185375 100644 --- a/pages/operators/manager/security.mdx +++ b/pages/operators/manager/security.mdx @@ -33,6 +33,22 @@ The manager handles kernel and disk image downloads automatically. If you deploy container-based blueprints, use a hardened runtime such as Kata Containers and follow Kubernetes best practices for least privilege. +When a blueprint or service runs with `tee_required`, missing Kata support should be treated as a hard error rather than a +reason to fall back silently to standard container execution. + +## Remote TEE attestation + +For remote confidential-compute deployments, operators should treat attestation as part of the deployment gate, not as an +optional afterthought. + +- `BLUEPRINT_REMOTE_TEE_ATTESTATION_POLICY=cryptographic` is the strongest mode and requires an executable verifier + command. +- `BLUEPRINT_REMOTE_TEE_ATTESTATION_POLICY=structural` is weaker, but still enforces TEE-aware provider selection. +- When TEE is required, provider selection should be limited to TEE-capable providers and should not fall back to + standard VMs. + +See [Confidential Compute](/operators/manager/confidential-compute) for the exact preflight workflow and environment. + ## Key and data safety - Store keystores on encrypted storage. diff --git a/pages/operators/manager/setup.mdx b/pages/operators/manager/setup.mdx index 4f4847fc..92a50d6e 100644 --- a/pages/operators/manager/setup.mdx +++ b/pages/operators/manager/setup.mdx @@ -61,3 +61,25 @@ cargo tangle blueprint run \ - The manager maintains a cache for downloaded artifacts (defaults to `./cache`). Plan capacity based on the number of services you expect to host. See [Sizing and Capacity](/operators/manager/sizing). + +## 5) Remote TEE preflight + +If you want to satisfy remote `tee_required` workloads, validate your cloud and attestation configuration before starting +the manager: + +```bash +cargo tangle cloud configure aws --region us-east-1 --set-default +cargo tangle cloud preflight --tee-required --bootstrap-env +``` + +The preflight flow prints the bootstrap environment expected by the manager, including: + +- `BLUEPRINT_REMOTE_TEE_REQUIRED=true` +- `BLUEPRINT_REMOTE_TEE_ATTESTATION_POLICY` +- `BLUEPRINT_REMOTE_TEE_ATTESTATION_VERIFY_CMD` for cryptographic verification +- `TEE_BACKEND` + +Use `--write-env-file` if you want to materialize that output into an env file for your supervisor. + +For local container TEE execution instead of remote provisioning, configure Kubernetes with the `kata` runtime class. See +[Confidential Compute](/operators/manager/confidential-compute). diff --git a/pages/operators/pricing/overview.mdx b/pages/operators/pricing/overview.mdx index efd8a8f7..3226d60f 100644 --- a/pages/operators/pricing/overview.mdx +++ b/pages/operators/pricing/overview.mdx @@ -41,6 +41,9 @@ These flows require operators to generate and sign EIP-712 quotes off-chain: - `PayOnce`: users create a service using `createServiceFromQuotes(...)`. - Job RFQ: users submit jobs using `submitJobFromQuote(...)`. +If the customer requests a specific confidentiality mode for the service, that confidentiality intent is part of the +service RFQ agreement and should be reflected in your quote and operating cost assumptions. + To participate in RFQ, you need: - a quote serving endpoint (typically the `pricing-engine` gRPC server) diff --git a/pages/operators/runbook.mdx b/pages/operators/runbook.mdx index 6455e19b..65110c03 100644 --- a/pages/operators/runbook.mdx +++ b/pages/operators/runbook.mdx @@ -8,6 +8,7 @@ This is a minimal operational checklist for keeping Blueprint services healthy a - Confirm service heartbeats are progressing (no sustained gaps). - Review job error rates and retry spikes. - Check disk usage for cache + data directories. +- For TEE-required workloads, confirm the active host or provider still satisfies the confidentiality policy. ## Key Signals to Watch @@ -15,6 +16,8 @@ This is a minimal operational checklist for keeping Blueprint services healthy a - **Job queue backlog**: growing queues indicate capacity pressure. - **RPC latency**: slow RPCs lead to missed service events. - **Crash loops**: repeated restarts usually imply config or artifact issues. +- **TEE prerequisite failures**: missing Kata, missing attestation verifier, or non-TEE provider selection should be + treated as deployment blockers, not degraded operation. ## Incident Response @@ -38,5 +41,6 @@ This is a minimal operational checklist for keeping Blueprint services healthy a ## Related Docs - [Blueprint Manager setup](/operators/manager/setup) +- [Confidential Compute](/operators/manager/confidential-compute) - [Quality of Service](/operators/quality-of-service) - [Benchmarking](/operators/benchmarking) diff --git a/scripts/check-tnt-core-sync.mjs b/scripts/check-tnt-core-sync.mjs new file mode 100644 index 00000000..0ed144fb --- /dev/null +++ b/scripts/check-tnt-core-sync.mjs @@ -0,0 +1,101 @@ +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, ".."); + +function resolveTntCoreDir() { + const explicit = process.env.TNT_CORE_DIR; + const candidates = [ + explicit && path.resolve(explicit), + path.resolve(repoRoot, "../tnt-core"), + path.resolve(repoRoot, "../../tnt-core"), + ].filter(Boolean); + + for (const candidate of candidates) { + if (fs.existsSync(path.join(candidate, "src/interfaces/ITangleServices.sol"))) { + return candidate; + } + } + + throw new Error( + `Unable to locate tnt-core checkout. Tried: ${candidates.join(", ")}`, + ); +} + +const tntCoreDir = resolveTntCoreDir(); + +const helperPath = path.join( + repoRoot, + "scripts/solidity-docgen/templates/helpers/index.cjs", +); +const sourcePath = path.join(tntCoreDir, "src/interfaces/ITangleServices.sol"); +const docsPaths = [ + path.join(repoRoot, "pages/developers/api/reference/ITangleServices.mdx"), + path.join(repoRoot, "pages/developers/api/reference/generated/ITangleServices.mdx"), +]; + +function readFile(targetPath) { + if (!fs.existsSync(targetPath)) { + throw new Error(`Missing required file: ${targetPath}`); + } + return fs.readFileSync(targetPath, "utf8"); +} + +function assertIncludes(haystack, needle, label) { + if (!haystack.includes(needle)) { + throw new Error(`${label} is missing required snippet:\n${needle}`); + } +} + +const helper = readFile(helperPath); +assertIncludes(helper, ': "main"', "solidity docgen helper"); + +const source = readFile(sourcePath).replace(/\s+/g, " "); +const requiredSourceSnippets = [ + "Types.ConfidentialityPolicy confidentiality", + "function getServiceRequestResourceRequirements(", + "function approveServiceWithBls(", + "function approveServiceWithCommitmentsAndBls(", + "function terminateServiceForNonPayment(", + "event ServiceTerminatedForNonPayment(", +]; + +for (const snippet of requiredSourceSnippets) { + assertIncludes(source, snippet, "ITangleServices.sol"); +} + +const docs = docsPaths.map((targetPath) => ({ + path: targetPath, + content: readFile(targetPath), +})); + +if (docs[0].content !== docs[1].content) { + throw new Error( + "ITangleServices reference pages diverged: keep generated/ and non-generated copies identical.", + ); +} + +const requiredDocsSnippets = [ + "function requestService(uint64 blueprintId, address[] operators, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount, enum Types.ConfidentialityPolicy confidentiality) external payable returns (uint64 requestId)", + "function requestServiceWithExposure(uint64 blueprintId, address[] operators, uint16[] exposureBps, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount, enum Types.ConfidentialityPolicy confidentiality) external payable returns (uint64 requestId)", + "function requestServiceWithSecurity(uint64 blueprintId, address[] operators, struct Types.AssetSecurityRequirement[] securityRequirements, bytes config, address[] permittedCallers, uint64 ttl, address paymentToken, uint256 paymentAmount, enum Types.ConfidentialityPolicy confidentiality) external payable returns (uint64 requestId)", + "function getServiceRequestResourceRequirements(uint64 requestId) external view returns (struct Types.ResourceCommitment[])", + "function approveServiceWithBls(uint64 requestId, uint8 stakingPercent, uint256[4] blsPubkey) external", + "function approveServiceWithCommitmentsAndBls(uint64 requestId, struct Types.AssetSecurityCommitment[] commitments, uint256[4] blsPubkey) external", + "function terminateServiceForNonPayment(uint64 serviceId) external", + "event ServiceRequested(uint64 requestId, uint64 blueprintId, address requester, enum Types.ConfidentialityPolicy confidentiality)", + "event ServiceRequestedWithSecurity(uint64 requestId, uint64 blueprintId, address requester, enum Types.ConfidentialityPolicy confidentiality)", + "event ServiceActivated(uint64 serviceId, uint64 requestId, uint64 blueprintId, enum Types.ConfidentialityPolicy confidentiality)", + "event ServiceTerminatedForNonPayment(uint64 serviceId, address triggeredBy, uint64 dueAt, uint64 graceEndsAt, uint256 requiredAmount, uint256 escrowBalance)", +]; + +for (const { path: targetPath, content } of docs) { + for (const snippet of requiredDocsSnippets) { + assertIncludes(content, snippet, targetPath); + } +} + +console.log("tnt-core sync checks passed"); diff --git a/scripts/solidity-docgen/templates/helpers/index.cjs b/scripts/solidity-docgen/templates/helpers/index.cjs index e2894389..599f8101 100644 --- a/scripts/solidity-docgen/templates/helpers/index.cjs +++ b/scripts/solidity-docgen/templates/helpers/index.cjs @@ -25,7 +25,7 @@ function githubSourceUrl(absolutePath) { const ref = process.env.TNT_CORE_GITHUB_REF && process.env.TNT_CORE_GITHUB_REF.length > 0 ? process.env.TNT_CORE_GITHUB_REF - : "feature/modular-protocol"; + : "main"; const rel = path.relative(repoRoot, absolutePath).split(path.sep).join("/"); return `${repo}/blob/${ref}/${rel}`; }