Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,10 @@ If a negotiation is successfully completed (termed *finalized*), a DSP contract
}
```

A provider can also hold contract negotiations for manual approval before the agreement is sent, for example for
requests from unknown counterparties. Which negotiations need approval is decided by the contract policy, see
[Contract Negotiation Approval](./policy-engine/negotiation-approval/_index.md).

EDC implements DSP message exchanges using a reliable quality of service. That is, all message operations and state machine transitions are performed reliably in a transaction context. EDC will only commit a state machine transition if a message is successfully acknowledged by the counterparty. If a send operation fails, the associated transition will be rolled back, and the message will be resent. As with all reliable messaging systems, EDC operations are idempotent.

### Working with Asynchronous Messaging and Events
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ weight: 10

<!-- TOC -->
* [CEL Policy Expressions](#cel-policy-expressions)
* [Contract Negotiation Approval](#contract-negotiation-approval)
* [Policy Scopes and Bindings](#policy-scopes-and-bindings)
* [Designing for Optimal Policy Performance](#designing-for-optimal-policy-performance)
* [In Force Policy](#in-force-policy)
Expand Down Expand Up @@ -106,6 +107,14 @@ credential-based rules, which ship with a set of ready-made helper functions.

See [CEL Policy Expressions](./cel/_index.md) for the details.

## Contract Negotiation Approval

The policy engine can also decide whether a provider contract negotiation needs to be approved manually before it
reaches an agreement. The contract policy is evaluated in the dedicated `approval.contract.negotiation` scope, and
negotiations that do not pass it are held until they are approved or rejected through the Management API.

See [Contract Negotiation Approval](./negotiation-approval/_index.md) for the details.

## Policy Scopes and Bindings

In EDC, policy rules are bound to a specific context termed a *scope*. EDC defines numerous scopes, such as one for
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,13 @@ used as a lookup key — but using a stable, namespaced IRI avoids collisions.
Policy rules are only evaluated in the [scopes](../_index.md#policy-scopes-and-bindings) they are bound to. A
`CelExpression` declares a set of `scopes`, and the engine binds the expression to exactly those policy phases:

| Scope value | Policy phase |
|------------------------|---------------------------------|
| `catalog` | catalog request |
| `contract.negotiation` | contract negotiation |
| `transfer.process` | transfer process |
| `policy.monitor` | policy monitor (ongoing checks) |
| Scope value | Policy phase |
|---------------------------------|--------------------------------------------------------------------|
| `catalog` | catalog request |
| `contract.negotiation` | contract negotiation |
| `approval.contract.negotiation` | [contract negotiation approval](../negotiation-approval/_index.md) |
| `transfer.process` | transfer process |
| `policy.monitor` | policy monitor (ongoing checks) |

If `scopes` is left empty it defaults to `*.` (match all scopes). Restrict the scopes to the phases where the
check is actually needed — for example, verifying a membership credential during negotiation but not again
Expand Down Expand Up @@ -187,12 +188,14 @@ an `error` if the expression failed to compile or evaluate):

Expressions are evaluated against a set of bound variables. What is available depends on the scope:

| Variable | Shape | Available in |
|-----------------|-----------------------------------------------------------------------------------------------|-------------------------------------------------|
| `ctx.agent` | `{ id, attributes, claims }` — the counterparty; `claims.vc` is the credential list | catalog, contract.negotiation, transfer.process |
| `ctx.agreement` | `{ id, assetId, providerId, consumerId, agreementId, contractSigningDate }` | transfer.process, policy.monitor |
| `this` | `{ leftOperand, operator, odrlOperator, rightOperand }` — the ODRL constraint being evaluated | all scopes |
| `now` | the current timestamp | all scopes |
| Variable | Shape | Available in |
|--------------------------|-----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|
| `ctx.agent` | `{ id, attributes, claims }` — the counterparty; `claims.vc` is the credential list | catalog, contract.negotiation, approval.contract.negotiation, transfer.process, policy.monitor |
| `ctx.agreement` | `{ id, assetId, providerId, consumerId, agreementId, contractSigningDate }` | transfer.process, policy.monitor |
| `ctx.asset` | `{ id, participantContextId, properties, privateProperties }` — the negotiated asset | approval.contract.negotiation |
| `ctx.contractDefinition` | `{ id, participantContextId, accessPolicyId, contractPolicyId, privateProperties, assetsSelector }` | approval.contract.negotiation |
| `this` | `{ leftOperand, operator, odrlOperator, rightOperand }` — the ODRL constraint being evaluated | all scopes |
| `now` | the current timestamp | all scopes |

`this.rightOperand` is the value declared on the policy constraint, so an expression can compare against it
rather than hard-coding a value.
Expand All @@ -206,8 +209,12 @@ this.odrlOperator == 'eq' ? ctx.agent.attributes.region == this.rightOperand
: ctx.agent.attributes.region in this.rightOperand
```

Alternatively, split the logic into separate expressions with [`supportedOperators`](#restricting-by-operator). Note that `ctx.agent` is **not** available in the `policy.monitor` scope,
which only exposes `ctx.agreement`.
Alternatively, split the logic into separate expressions with [`supportedOperators`](#restricting-by-operator).

In the `policy.monitor` and `approval.contract.negotiation` scopes there is no incoming request, so `ctx.agent` is
rebuilt from the claims stored when they were received: on the contract agreement for the policy monitor (with the
consumer as identity), and on the contract negotiation for the approval. The claims, credentials included, are not
verified again at evaluation time.

_In CEL, reading a map key that is absent aborts evaluation with an error — it does not return `false`. Guard
raw map access with the `has()` macro, or prefer the Verifiable Credential helper functions below, which are
Expand Down
Loading
Loading