diff --git a/README.md b/README.md index 73daa76..4ecf538 100644 --- a/README.md +++ b/README.md @@ -338,44 +338,10 @@ to select the ## Transfer Data Now that both participants are set up, we can transfer data from the Provider to the Consumer. -There are two use case supported here: +The only use case supported here: -- Http proxy - Certificates sharing via HTTP -### Http proxy - -EDC-V offers a one-stop-shop API to transfer data. This is achieved by two endpoints, one that fetches the catalog ( -`Data Transfer/Http Todo/Get Catalog`) and another endpoint (`Data Transfer/Http Todo/Get Data`) that initiates the -contract negotiation, -waits for its successful completion, then starts the data transfer. - -Perform the entire sequence by running both requests in the `Data Transfer/Http Todo` folder in Bruno: - -![img.png](docs/images/bruno_transfer.png) - -This will request the catalog, which contains exactly one dataset, then initiates contract negotiation and data -transfer for that asset. If everything went well, the output should contain demo output -from , something like: - -```json lines -[ - { - "userId": 1, - "id": 1, - "title": "delectus aut autem", - "completed": false - }, - { - "userId": 1, - "id": 2, - "title": "quis ut nam facilis et officia qui", - "completed": false - } - //... -] -``` - ### Certificates sharing via HTTP The second use case demonstrates how certificates can be shared between participants using EDC-V's HTTP data @@ -396,7 +362,10 @@ Then perform the entire sequence by running both requests in the `Data Transfer/ which: - Fetches the catalog from the Provider storing the offer id for the certificate asset -- Setup the transfer request using the offer id (contract negotiation + transfer initiation) storing the access token +- Setup the Contract negotiation using the offer id +- Poll the Contract Negotiation for the agreement id if the negotiation is successful +- Setup the transfer request for the agreement id of the previous step +- Fetch the access token for the transfer request (Siglet) - Query the provider for listing the available certificates storing the first certificate id - Finally, download the certificate using the certificate id diff --git a/docs/images/bruno_certificate_consumer.png b/docs/images/bruno_certificate_consumer.png index e660e2a..feef4c9 100644 Binary files a/docs/images/bruno_certificate_consumer.png and b/docs/images/bruno_certificate_consumer.png differ diff --git a/extensions/api/mgmt/build.gradle.kts b/extensions/api/mgmt/build.gradle.kts deleted file mode 100644 index 6492733..0000000 --- a/extensions/api/mgmt/build.gradle.kts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2025 Metaform Systems, Inc. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Metaform Systems, Inc. - initial API and implementation - * - */ - -plugins { - `java-library` - id("io.swagger.core.v3.swagger-gradle-plugin") - -} - -dependencies { - // todo: replace with SPI - implementation(libs.edc.vault.hashicorp) - implementation(libs.edc.spi.participantcontext) - implementation(libs.edc.core.jersey) - implementation(libs.edc.core.jetty) - implementation(libs.edc.spi.web) - implementation(libs.edc.spi.controlplane) - implementation(libs.edc.spi.participantcontext.config) - implementation(libs.edc.spi.transaction) - implementation(libs.edc.spi.edrstore) - - implementation(libs.edc.did.core) -} diff --git a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/ApiExtension.java b/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/ApiExtension.java deleted file mode 100644 index c36f0dc..0000000 --- a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/ApiExtension.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2025 Metaform Systems, Inc. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Metaform Systems, Inc. - initial API and implementation - * - */ - -package org.eclipse.edc.virtualized; - -import org.eclipse.edc.connector.controlplane.services.spi.catalog.CatalogService; -import org.eclipse.edc.connector.controlplane.services.spi.contractnegotiation.ContractNegotiationService; -import org.eclipse.edc.connector.controlplane.services.spi.transferprocess.TransferProcessService; -import org.eclipse.edc.edr.spi.store.EndpointDataReferenceStore; -import org.eclipse.edc.iam.did.spi.resolution.DidResolverRegistry; -import org.eclipse.edc.participantcontext.spi.service.ParticipantContextService; -import org.eclipse.edc.runtime.metamodel.annotation.Inject; -import org.eclipse.edc.spi.system.ServiceExtension; -import org.eclipse.edc.spi.system.ServiceExtensionContext; -import org.eclipse.edc.virtualized.api.data.DataApiController; -import org.eclipse.edc.virtualized.service.DataRequestService; -import org.eclipse.edc.web.spi.WebService; -import org.eclipse.edc.web.spi.configuration.ApiContext; - - -public class ApiExtension implements ServiceExtension { - @Inject - private WebService webService; - - @Inject - private CatalogService catalogService; - @Inject - private DidResolverRegistry didResolverRegistry; - @Inject - private ParticipantContextService participantContextService; - @Inject - private ContractNegotiationService contractNegotiationService; - @Inject - private TransferProcessService transferProcessService; - @Inject - private EndpointDataReferenceStore edrStore; - - @Override - public void initialize(ServiceExtensionContext context) { - var dataRequestService = new DataRequestService(contractNegotiationService, transferProcessService, didResolverRegistry, edrStore); - webService.registerResource(ApiContext.MANAGEMENT, new DataApiController(catalogService, didResolverRegistry, participantContextService, dataRequestService)); - } - - -} - - diff --git a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/ControlApiUrlExtension.java b/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/ControlApiUrlExtension.java deleted file mode 100644 index e63c72f..0000000 --- a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/ControlApiUrlExtension.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2026 Metaform Systems, Inc. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Metaform Systems, Inc. - initial API and implementation - * - */ - -package org.eclipse.edc.virtualized; - -import org.eclipse.edc.runtime.metamodel.annotation.Configuration; -import org.eclipse.edc.runtime.metamodel.annotation.Extension; -import org.eclipse.edc.runtime.metamodel.annotation.Provider; -import org.eclipse.edc.runtime.metamodel.annotation.Setting; -import org.eclipse.edc.runtime.metamodel.annotation.Settings; -import org.eclipse.edc.spi.system.ServiceExtension; -import org.eclipse.edc.web.spi.configuration.ApiContext; -import org.eclipse.edc.web.spi.configuration.context.ControlApiUrl; - -import java.net.URI; - -import static org.eclipse.edc.virtualized.ControlApiUrlExtension.NAME; - -@Extension(value = NAME) -public class ControlApiUrlExtension implements ServiceExtension { - public static final String NAME = "EDC-V Control API URL Extension"; - @Configuration - private ControlApiConfiguration controlApiConfiguration; - - @Provider - public ControlApiUrl controlApiUrl() { - return () -> URI.create("http://controlplane.edc-v.svc.cluster.local:%s%s".formatted(controlApiConfiguration.port(), controlApiConfiguration.path())); - } - - @Settings - record ControlApiConfiguration( - @Setting(key = "web.http." + ApiContext.CONTROL + ".port", description = "Port for " + ApiContext.CONTROL + " api context") - int port, - @Setting(key = "web.http." + ApiContext.CONTROL + ".path", description = "Path for " + ApiContext.CONTROL + " api context") - String path - ) { - - } -} diff --git a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/api/data/CatalogRequest.java b/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/api/data/CatalogRequest.java deleted file mode 100644 index e5da015..0000000 --- a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/api/data/CatalogRequest.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2025 Metaform Systems, Inc. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Metaform Systems, Inc. - initial API and implementation - * - */ - -package org.eclipse.edc.virtualized.api.data; - -import org.eclipse.edc.spi.query.QuerySpec; - -public final class CatalogRequest { - private String counterPartyDid; - private String protocol = "dataspace-protocol-http:2025-1"; - private QuerySpec query = QuerySpec.max(); - - public String getCounterPartyDid() { - return counterPartyDid; - } - - public void setCounterPartyDid(String counterPartyDid) { - this.counterPartyDid = counterPartyDid; - } - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - public QuerySpec getQuery() { - return query; - } - - public void setQuery(QuerySpec query) { - this.query = query; - } -} diff --git a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/api/data/DataApiController.java b/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/api/data/DataApiController.java deleted file mode 100644 index a91c971..0000000 --- a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/api/data/DataApiController.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2025 Metaform Systems, Inc. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Metaform Systems, Inc. - initial API and implementation - * - */ - -package org.eclipse.edc.virtualized.api.data; - -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.container.AsyncResponse; -import jakarta.ws.rs.container.Suspended; -import jakarta.ws.rs.core.Response; -import org.eclipse.edc.connector.controlplane.services.spi.catalog.CatalogService; -import org.eclipse.edc.iam.did.spi.resolution.DidResolverRegistry; -import org.eclipse.edc.participantcontext.spi.service.ParticipantContextService; -import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.spi.response.StatusResult; -import org.eclipse.edc.virtualized.service.DataRequestService; -import org.eclipse.edc.web.spi.exception.BadGatewayException; - -import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; - -/** - * This controller is a quick workaround so that we are able to get a catalog from a counter-party, and to trigger the all-in-one data transfer. - * see {@link DataRequestService} for more details. - */ -@Consumes(APPLICATION_JSON) -@Produces(APPLICATION_JSON) -@Path("/v1alpha/participants/{participantContextId}/") -public class DataApiController { - - private final CatalogService service; - private final DidResolverRegistry didResolverRegistry; - private final ParticipantContextService participantContextService; - private final DataRequestService dataRequestService; - - public DataApiController(CatalogService service, DidResolverRegistry didResolverRegistry, ParticipantContextService participantContextService, DataRequestService dataRequestService) { - this.service = service; - this.didResolverRegistry = didResolverRegistry; - this.participantContextService = participantContextService; - this.dataRequestService = dataRequestService; - } - - - @POST - @Path("/catalog") - public void getCatalog(@PathParam("participantContextId") String participantContextId, - CatalogRequest catalogRequest, - @Suspended AsyncResponse response) { - - var participantContext = participantContextService.getParticipantContext(participantContextId); - if (participantContext.failed()) { - response.resume(Response.status(404).entity("Participant context '%s' not found".formatted(participantContextId)).build()); - } - - var counterPartyDid = catalogRequest.getCounterPartyDid(); - var did = didResolverRegistry.resolve(counterPartyDid); - if (did.failed()) { - response.resume(Response.status(400).entity("Could not resolve DID '%s': %s".formatted(counterPartyDid, did.getFailureDetail())).build()); - } - - var doc = did.getContent(); - - var protocolEndpoint = doc.getService().stream().filter(s -> s.getType().equals("ProtocolEndpoint")).findFirst(); - if (protocolEndpoint.isEmpty()) { - response.resume(Response.status(400).entity("No ProtocolEndpoint service found in DID Document for '%s'".formatted(counterPartyDid)).build()); - return; - } - var counterPartyAddress = protocolEndpoint.get().getServiceEndpoint(); - var catalog = service.requestCatalog(participantContext.getContent(), counterPartyDid, counterPartyAddress, catalogRequest.getProtocol(), catalogRequest.getQuery()); - - catalog.whenComplete((result, throwable) -> { - try { - response.resume(toResponse(result, throwable)); - } catch (Throwable mapped) { - response.resume(mapped); - } - }); - - } - - @POST - @Path("/transfer") - public void setupTransfer(@PathParam("participantContextId") String participantContextId, DataRequest dataRequest, @Suspended AsyncResponse response) { - var participantContext = participantContextService.getParticipantContext(participantContextId); - if (participantContext.failed()) { - response.resume(Response.status(404).entity("Participant context '%s' not found".formatted(participantContextId)).build()); - } - dataRequestService.setupTransfer(participantContext.getContent(), dataRequest) - .whenComplete((result, throwable) -> { - try { - if (throwable != null) { - response.resume(Response.status(500).entity(throwable.getMessage()).build()); - - } else if (result.succeeded()) { - response.resume(result.getContent()); - } else { - response.resume(Response.status(500).entity(result.getFailureDetail()).build()); - } - } catch (Throwable mapped) { - response.resume(Response.status(500).entity(mapped.getMessage()).build()); - } - }); - } - - @GET - @Path("/edr/{transferProcessId}") - public void getEdr(@PathParam("participantContextId") String participantContextId, @PathParam("transferProcessId") String transferProcessId, @Suspended AsyncResponse response) { - var participantContext = participantContextService.getParticipantContext(participantContextId); - if (participantContext.failed()) { - response.resume(Response.status(404).entity("Participant context '%s' not found".formatted(participantContextId)).build()); - } - dataRequestService.getEdr(transferProcessId) - .whenComplete((result, throwable) -> { - try { - if (throwable != null) { - response.resume(throwable); - } - response.resume(result); - } catch (Throwable mapped) { - response.resume(mapped); - } - }); - } - - private T toResponse(StatusResult result, Throwable throwable) throws Throwable { - if (throwable == null) { - if (result.succeeded()) { - return result.getContent(); - } else { - throw new BadGatewayException(result.getFailureDetail()); - } - } else { - if (throwable instanceof EdcException || throwable.getCause() instanceof EdcException) { - throw new BadGatewayException(throwable.getMessage()); - } else { - throw throwable; - } - } - } - -} diff --git a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/api/data/DataRequest.java b/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/api/data/DataRequest.java deleted file mode 100644 index 5e3b423..0000000 --- a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/api/data/DataRequest.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2025 Metaform Systems, Inc. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Metaform Systems, Inc. - initial API and implementation - * - */ - -package org.eclipse.edc.virtualized.api.data; - -import org.jetbrains.annotations.Nullable; - -public record DataRequest( - String providerId, - String policyId, - @Nullable String policyType -) { -} diff --git a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/service/Data.java b/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/service/Data.java deleted file mode 100644 index 190ba24..0000000 --- a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/service/Data.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2025 Metaform Systems, Inc. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Metaform Systems, Inc. - initial API and implementation - * - */ - -package org.eclipse.edc.virtualized.service; - -import org.eclipse.edc.policy.model.Action; -import org.eclipse.edc.policy.model.AtomicConstraint; -import org.eclipse.edc.policy.model.LiteralExpression; -import org.eclipse.edc.policy.model.Operator; -import org.eclipse.edc.policy.model.Permission; -import org.eclipse.edc.policy.model.Policy; - -import java.util.Map; - -public class Data { - public static final Policy MEMBERSHIP_POLICY = Policy.Builder.newInstance() - .permission(Permission.Builder.newInstance() - .action(Action.Builder.newInstance() - .type("http://www.w3.org/ns/odrl/2/use") - .build()) - .constraint(AtomicConstraint.Builder.newInstance() - .leftExpression(new LiteralExpression("MembershipCredential")) - .operator(Operator.EQ) - .rightExpression(new LiteralExpression("active")) - .build()) - .build()) - .build(); - - public static final Policy MANUFACTURER_POLICY = Policy.Builder.newInstance() - .permission(Permission.Builder.newInstance() - .action(Action.Builder.newInstance() - .type("http://www.w3.org/ns/odrl/2/use") - .build()) - .constraint(AtomicConstraint.Builder.newInstance() - .leftExpression(new LiteralExpression("ManufacturerCredential")) - .operator(Operator.EQ) - .rightExpression(new LiteralExpression("active")) - .build()) - .build()) - .build(); - - public static final Map POLICY_MAP = Map.of("membership", MEMBERSHIP_POLICY, "manufacturer", MANUFACTURER_POLICY); -} diff --git a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/service/DataRequestService.java b/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/service/DataRequestService.java deleted file mode 100644 index 8948925..0000000 --- a/extensions/api/mgmt/src/main/java/org/eclipse/edc/virtualized/service/DataRequestService.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2025 Metaform Systems, Inc. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Metaform Systems, Inc. - initial API and implementation - * - */ - -package org.eclipse.edc.virtualized.service; - -import org.eclipse.edc.connector.controlplane.contract.spi.ContractOfferId; -import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiationStates; -import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractRequest; -import org.eclipse.edc.connector.controlplane.contract.spi.types.offer.ContractOffer; -import org.eclipse.edc.connector.controlplane.services.spi.contractnegotiation.ContractNegotiationService; -import org.eclipse.edc.connector.controlplane.services.spi.transferprocess.TransferProcessService; -import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; -import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcessStates; -import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferRequest; -import org.eclipse.edc.edr.spi.store.EndpointDataReferenceStore; -import org.eclipse.edc.iam.did.spi.document.Service; -import org.eclipse.edc.iam.did.spi.resolution.DidResolverRegistry; -import org.eclipse.edc.participantcontext.spi.types.ParticipantContext; -import org.eclipse.edc.policy.model.PolicyType; -import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.spi.result.Result; -import org.eclipse.edc.spi.result.ServiceResult; -import org.eclipse.edc.spi.types.domain.DataAddress; -import org.eclipse.edc.virtualized.api.data.DataRequest; - -import java.net.URI; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -import static java.net.http.HttpClient.newHttpClient; -import static java.util.Optional.ofNullable; -import static org.eclipse.edc.virtualized.service.Data.MEMBERSHIP_POLICY; -import static org.eclipse.edc.virtualized.service.Data.POLICY_MAP; - -/** - * this is a wrapper service that initiates the contract negotiation and the transfer process, waits for its completion, and then downloads the data. - * I implemented this because there is no multi-tenant management API yet that. - */ -public class DataRequestService { - - private final ContractNegotiationService contractNegotiationService; - private final TransferProcessService transferProcessService; - private final DidResolverRegistry didResolverRegistry; - private final EndpointDataReferenceStore edrStore; - - public DataRequestService(ContractNegotiationService contractNegotiationService, TransferProcessService transferProcessService, DidResolverRegistry didResolverRegistry, EndpointDataReferenceStore edrStore) { - this.contractNegotiationService = contractNegotiationService; - this.transferProcessService = transferProcessService; - this.didResolverRegistry = didResolverRegistry; - this.edrStore = edrStore; - } - - public CompletableFuture>> setupTransfer(ParticipantContext participantContext, DataRequest dataRequest) { - return initiateContractNegotiation(participantContext, dataRequest) - .thenCompose(this::waitForContractNegotiation) - .thenCompose(contractNegotiation -> startTransferProcess(participantContext, contractNegotiation)) - .thenCompose(this::waitForTransferProcess) - .thenCompose(transferProcess -> getEdr(transferProcess.getId())) - .thenCompose(edr -> CompletableFuture.completedFuture(edr.getProperties())) - .thenApply(ServiceResult::success); - } - - public CompletableFuture getEdr(String transferProcessId) { - var edr = edrStore.resolveByTransferProcess(transferProcessId); - if (edr.failed()) { - return CompletableFuture.failedFuture(new EdcException("Could not resolve EDR for transfer process: %s".formatted(edr.getFailureDetail()))); - } - return CompletableFuture.completedFuture(edr.getContent()); - } - - private CompletableFuture initiateContractNegotiation(ParticipantContext participantContext, DataRequest dataRequest) { - var addressForDid = getAddressForDid(dataRequest.providerId()); - if (addressForDid.failed()) { - return CompletableFuture.failedFuture(new RuntimeException("Could not resolve address for did: %s".formatted(addressForDid.getFailureDetail()))); - } - - var policy = ofNullable(dataRequest.policyType()).map(POLICY_MAP::get).orElse(MEMBERSHIP_POLICY); - - var offerId = ContractOfferId.parseId(dataRequest.policyId()); - var rq = ContractRequest.Builder.newInstance() - .protocol("dataspace-protocol-http:2025-1") - .counterPartyAddress(addressForDid.getContent()) - .contractOffer(ContractOffer.Builder.newInstance() - .id(dataRequest.policyId()) - .assetId(offerId.getContent().assetIdPart()) - .policy(policy.toBuilder() - .target(offerId.getContent().assetIdPart()) - .assigner(dataRequest.providerId()) - .type(PolicyType.OFFER) - .build()) - .build()) - .build(); - var result = contractNegotiationService.initiateNegotiation(participantContext, rq); - if (result.failed()) { - return CompletableFuture.failedFuture(new EdcException("Could not initiate contract negotiation: %s ".formatted(result.getFailureDetail()))); - } - return CompletableFuture.completedFuture(result.getContent().getId()); - - } - - private Result getAddressForDid(String counterPartyDid) { - var did = didResolverRegistry.resolve(counterPartyDid); - if (did.failed()) { - return did.mapFailure(); - } - - var doc = did.getContent(); - - var protocolEndpoint = doc.getService().stream().filter(s -> s.getType().equals("ProtocolEndpoint")).findFirst(); - return Result.from(protocolEndpoint).map(Service::getServiceEndpoint); - } - - private CompletableFuture waitForContractNegotiation(String contractNegotiationId) { - - try { - ContractNegotiationStates state; - do { - state = ContractNegotiationStates.valueOf(contractNegotiationService.getState(contractNegotiationId)); - Thread.sleep(1000); - } while (state != ContractNegotiationStates.FINALIZED && state != ContractNegotiationStates.TERMINATED); - - if (state == ContractNegotiationStates.TERMINATED) { - return CompletableFuture.failedFuture(new EdcException("Contract negotiation terminated")); - } - - return CompletableFuture.completedFuture(contractNegotiationService.getForNegotiation(contractNegotiationId)); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return CompletableFuture.failedFuture(e); - } - } - - private CompletableFuture startTransferProcess(ParticipantContext participantContext, ContractAgreement agreement) { - - var request = TransferRequest.Builder.newInstance() - .contractId(agreement.getId()) - .counterPartyAddress(getAddressForDid(agreement.getProviderId()).getContent()) - .protocol("dataspace-protocol-http:2025-1") - .transferType("HttpData-PULL") - .dataDestination(DataAddress.Builder.newInstance().type("httpData").build()) - .build(); - - var result = transferProcessService.initiateTransfer(participantContext, request); - if (result.succeeded()) { - return CompletableFuture.completedFuture(result.getContent()); - } else { - return CompletableFuture.failedFuture(new EdcException("Could not start transfer process: %s".formatted(result.getFailureDetail()))); - } - } - - private CompletableFuture waitForTransferProcess(TransferProcess transferProcess) { - try { - TransferProcessStates state; - do { - state = TransferProcessStates.valueOf(transferProcessService.getState(transferProcess.getId())); - Thread.sleep(1000); - } while (state != TransferProcessStates.STARTED && state != TransferProcessStates.TERMINATED); - - var tp = transferProcessService.findById(transferProcess.getId()); - if (state == TransferProcessStates.TERMINATED) { - return CompletableFuture.failedFuture(new EdcException("Transfer process terminated: %s".formatted(ofNullable(tp).map(TransferProcess::getErrorDetail).orElse("provider terminated")))); - } - return CompletableFuture.completedFuture(tp); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return CompletableFuture.failedFuture(e); - } - } - - - private CompletableFuture downloadData(DataAddress edr) { - - // make HTTP request - if (edr.getType().equals("https://w3id.org/idsa/v4.1/HTTP")) { - - var endpoint = edr.getStringProperty("https://w3id.org/edc/v0.0.1/ns/endpoint"); - var token = edr.getStringProperty("https://w3id.org/edc/v0.0.1/ns/authorization"); - var authType = edr.getStringProperty("https://w3id.org/edc/v0.0.1/ns/authType"); - - if (endpoint == null) { - return CompletableFuture.failedFuture(new EdcException("Endpoint not found in EDR")); - } - - var request = HttpRequest.newBuilder(URI.create(endpoint)) - .GET() - .header("Authorization", token) - .build(); - return newHttpClient().sendAsync(request, HttpResponse.BodyHandlers.ofString()) - .thenCompose(response -> { - if (response.statusCode() >= 200 && response.statusCode() < 300) { - return CompletableFuture.completedFuture(response.body()); - } - return CompletableFuture.failedFuture(new EdcException("Dataplane request failed: HTTP Status code: %s, message: %s".formatted(response.statusCode(), response.body()))); - }); - } - return CompletableFuture.failedFuture(new EdcException("EDR type not supported: %s".formatted(edr.getType()))); - } -} diff --git a/extensions/api/mgmt/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/api/mgmt/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension deleted file mode 100644 index 436e319..0000000 --- a/extensions/api/mgmt/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright (c) 2025 Metaform Systems, Inc. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License, Version 2.0 which is available at -# https://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -# -# Contributors: -# Metaform Systems, Inc. - initial API and implementation -# -# - -org.eclipse.edc.virtualized.ApiExtension -org.eclipse.edc.virtualized.ControlApiUrlExtension \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 142321b..c6cdcb4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,12 +17,10 @@ opentelemetry = "2.26.1" [libraries] # upstream EDC dependencies -edc-did-core = { module = "org.eclipse.edc:identity-did-core", version.ref = "edc" } edc-core-boot = { module = "org.eclipse.edc:boot", version.ref = "edc" } edc-core-runtime = { module = "org.eclipse.edc:runtime-core", version.ref = "edc" } edc-core-token = { module = "org.eclipse.edc:token-core", version.ref = "edc" } edc-core-jersey = { module = "org.eclipse.edc:jersey-core", version.ref = "edc" } -edc-core-jetty = { module = "org.eclipse.edc:jetty-core", version.ref = "edc" } edc-core-api = { module = "org.eclipse.edc:api-core", version.ref = "edc" } edc-core-participantcontext-config = { module = "org.eclipse.edc:participant-context-config-core", version.ref = "edc" } edc-junit = { module = "org.eclipse.edc:junit", version.ref = "edc" } @@ -33,8 +31,6 @@ edc-lib-util = { module = "org.eclipse.edc:util-lib", version.ref = "edc" } edc-lib-sql = { module = "org.eclipse.edc:sql-lib", version.ref = "edc" } edc-lib-token = { module = "org.eclipse.edc:token-lib", version.ref = "edc" } edc-lib-oauth2-authn = { module = "org.eclipse.edc:auth-authentication-oauth2-lib", version.ref = "edc" } -edc-core-edrstore = { module = "org.eclipse.edc:edr-store-core", version.ref = "edc" } -edc-edrstore-receiver = { module = "org.eclipse.edc:edr-store-receiver", version.ref = "edc" } edc-core-sql-bootstrapper = { module = "org.eclipse.edc:sql-bootstrapper", version.ref = "edc" } edc-core-http = { module = "org.eclipse.edc:http", version.ref = "edc" } edc-core-sql = { module = "org.eclipse.edc:sql-core", version.ref = "edc" } @@ -43,16 +39,13 @@ edc-transaction-local = { module = "org.eclipse.edc:transaction-local", version. edc-transaction-pool = { module = "org.eclipse.edc:sql-pool-apache-commons", version.ref = "edc" } edc-api-control-configuration = { module = "org.eclipse.edc:control-api-configuration", version.ref = "edc" } edc-api-observability = { module = "org.eclipse.edc:api-observability", version.ref = "edc" } +edc-fixtures-mgmtapi = { module = "org.eclipse.edc:management-api-test-fixtures", version.ref = "edc" } # EDC spi dependencies -edc-spi-participantcontext = { module = "org.eclipse.edc:connector-participant-context-spi", version.ref = "edc" } -edc-spi-participantcontext-config = { module = "org.eclipse.edc:participant-context-config-spi", version.ref = "edc" } edc-spi-web = { module = "org.eclipse.edc:web-spi", version.ref = "edc" } -edc-spi-controlplane = { module = "org.eclipse.edc:control-plane-spi", version.ref = "edc" } edc-spi-http = { module = "org.eclipse.edc:http-spi", version.ref = "edc" } edc-spi-catalog = { module = "org.eclipse.edc:catalog-spi", version.ref = "edc" } edc-spi-transaction = { module = "org.eclipse.edc:transaction-spi", version.ref = "edc" } -edc-spi-edrstore = { module = "org.eclipse.edc:edr-store-spi", version.ref = "edc" } edc-spi-jwt = { module = "org.eclipse.edc:jwt-spi", version.ref = "edc" } # identityhub SPI modules diff --git a/k8s/apps/siglet-config.yaml b/k8s/apps/siglet-config.yaml index 1e9ad3b..48f05ad 100644 --- a/k8s/apps/siglet-config.yaml +++ b/k8s/apps/siglet-config.yaml @@ -19,11 +19,10 @@ metadata: namespace: edc-v data: siglet.toml: | - storage_backend = "postgres" - postgres_url = "postgresql://siglet:siglet@postgres:5432/sigletdb" - postgres_encryption_password = "mysecretpassword" - postgres_encryption_salt = "6b9768804c86626227e61acd9e06f8ff" token_server_secret = "93d22865c1b0695d3caa1ac5ba648b88942aaeee3b05ba4aff2efc87e2cd1944" + [storage_backend] + type = "postgres-vault" + url = "postgresql://siglet:siglet@postgres:5432/sigletdb" [[transfer_types]] transfer_type = "HttpData-PULL" endpoint_type = "HTTP" diff --git a/k8s/apps/siglet.yaml b/k8s/apps/siglet.yaml index 1c93542..b917a89 100644 --- a/k8s/apps/siglet.yaml +++ b/k8s/apps/siglet.yaml @@ -66,23 +66,23 @@ spec: env: - name: RUST_LOG value: "info,siglet=debug" - - name: SIGLET_SIGLET_API_PORT + - name: SIGLET__SIGLET_API_PORT value: "8080" - - name: SIGLET_SIGNALING_PORT + - name: SIGLET__SIGNALING_PORT value: "8081" - - name: SIGLET_REFRESH_API_PORT + - name: SIGLET__REFRESH_API_PORT value: "8082" - name: SIGLET_CONFIG_FILE value: "/config/siglet.toml" - - name: SIGLET_VAULT_URL + - name: SIGLET__VAULT__URL value: "http://vault:8200" - - name: SIGLET_VAULT_TOKEN_FILE + - name: SIGLET__VAULT__TOKEN_FILE value: "/vault/secrets/.vault-token" - - name: SIGLET_VAULT_SIGNING_KEY_NAME + - name: SIGLET__VAULT__SIGNING_KEY_NAME value: "signing-siglet" - - name: SIGLET_TOKEN_ISSUER + - name: SIGLET__TOKEN__ISSUER value: "siglet-issuer" - - name: SIGLET_TOKEN_REFRESH_ENDPOINT + - name: SIGLET__TOKEN__REFRESH_ENDPOINT value: "http://siglet.edc-v.svc.cluster.local:8082/token/refresh" volumeMounts: - name: siglet-config diff --git a/k8s/base/vault.yaml b/k8s/base/vault.yaml index 11a93fb..2e2f904 100644 --- a/k8s/base/vault.yaml +++ b/k8s/base/vault.yaml @@ -193,6 +193,11 @@ spec: path "sys/health" { capabilities = ["read"] } + + # TODO revisit these permissions, we may want to scope them down further + path "secret/*" { + capabilities = ["create", "read", "update", "delete", "list"] + } # Allow access to Transit engine for JWT signing path "transit/sign/*" { diff --git a/launchers/controlplane/build.gradle.kts b/launchers/controlplane/build.gradle.kts index 49baee0..b403467 100644 --- a/launchers/controlplane/build.gradle.kts +++ b/launchers/controlplane/build.gradle.kts @@ -25,15 +25,8 @@ dependencies { runtimeOnly(libs.edcv.bom.controlplane.nats) runtimeOnly(libs.edcv.bom.controlplane.dcp) runtimeOnly(libs.edc.spi.jwt) - - runtimeOnly(libs.edc.core.edrstore) runtimeOnly(libs.edc.vault.hashicorp) - runtimeOnly(libs.edc.edrstore.receiver) - runtimeOnly(libs.bouncyCastle.bcprovJdk18on) - - runtimeOnly(project(":extensions:api:mgmt")) - runtimeOnly(libs.opentelemetry.exporter.otlp) } diff --git a/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Fetch Token.bru b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Fetch Token.bru new file mode 100644 index 0000000..474fcad --- /dev/null +++ b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Fetch Token.bru @@ -0,0 +1,35 @@ +meta { + name: Fetch Token + type: http + seq: 5 +} + +get { + url: {{sigletBaseUrl}}/tokens/{{consumer_id}}/{{TRANSFER_ID}} + body: json + auth: none +} + +script:post-response { + try { + const json = res.getBody(); + const accessToken = json['token']; + + if (accessToken && typeof accessToken === 'string') { + bru.setVar('ACCESS_TOKEN', accessToken); + } else { + console.warn('Access Token not found'); + } + + } catch (e) { + console.error('Failed to parse response or set Access Token:', e); + test('Response is valid JSON', function () { + throw e; + }); + } +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Get Catalog.bru b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Get Catalog.bru index 5ce6c0f..22cae31 100644 --- a/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Get Catalog.bru +++ b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Get Catalog.bru @@ -5,14 +5,20 @@ meta { } post { - url: {{cpBaseUrl}}/api/mgmt/v1alpha/participants/{{consumer_id}}/catalog + url: {{cpBaseUrl}}/api/mgmt/v5beta/participants/{{consumer_id}}/catalog/request body: json auth: inherit } body:json { { - "counterPartyDid": "did:web:identityhub.edc-v.svc.cluster.local%3A7083:provider" + "@context": [ + "https://w3id.org/edc/connector/management/v2" + ], + "@type": "CatalogRequest", + "protocol": "dataspace-protocol-http:2025-1", + "counterPartyAddress": "http://controlplane.edc-v.svc.cluster.local:8082/api/dsp/{{provider_id}}/2025-1", + "counterPartyId": "did:web:identityhub.edc-v.svc.cluster.local%3A7083:provider" } } @@ -31,6 +37,7 @@ script:post-response { if (policyId && typeof policyId === 'string') { bru.setVar('POLICY_ID', policyId); + bru.setVar("DATASET_ID",assetId); console.log('Offer ID (POLICY_ID) is:', policyId); } else { console.warn('Policy ID not found in response at dataset[0].hasPolicy[0]["@id"]'); diff --git a/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Get certificate.bru b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Get certificate.bru index 41948e6..0aec853 100644 --- a/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Get certificate.bru +++ b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Get certificate.bru @@ -1,7 +1,7 @@ meta { name: Get certificate type: http - seq: 4 + seq: 7 } get { diff --git a/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/List certificates.bru b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/List certificates.bru index 8d7331b..f1bafc3 100644 --- a/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/List certificates.bru +++ b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/List certificates.bru @@ -1,7 +1,7 @@ meta { name: List certificates type: http - seq: 3 + seq: 6 } post { diff --git a/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Poll Contract Negotiation.bru b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Poll Contract Negotiation.bru new file mode 100644 index 0000000..a166257 --- /dev/null +++ b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Poll Contract Negotiation.bru @@ -0,0 +1,41 @@ +meta { + name: Poll Contract Negotiation + type: http + seq: 3 +} + +get { + url: {{cpBaseUrl}}/api/mgmt/v5beta/participants/{{consumer_id}}/contractnegotiations/{{NEGOTIATION_ID}} + body: json + auth: inherit +} + +script:post-response { + try { + const json = res.getBody(); + const contractAgreementId = json["contractAgreementId"]; + + if (contractAgreementId && typeof contractAgreementId === 'string') { + bru.setVar('AGREEMENT_ID', contractAgreementId); + console.log('Agreement ID (AGREEMENT_ID) is:', contractAgreementId); + } else { + console.warn('Agreement ID not found in response at json["contractAgreementId"]'); + } + + // Optional: assertion to ensure it exists + test('Agreement ID is present and stored', function () { + expect(contractAgreementId, 'Agreement ID should exist').to.be.a('string').and.not.empty; + }); + + } catch (e) { + console.error('Failed to parse response or set AGREEMENT_ID:', e); + test('Response is valid JSON', function () { + throw e; + }); + } +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Setup Contract Negotiation.bru b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Setup Contract Negotiation.bru new file mode 100644 index 0000000..1b634e4 --- /dev/null +++ b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Setup Contract Negotiation.bru @@ -0,0 +1,70 @@ +meta { + name: Setup Contract Negotiation + type: http + seq: 2 +} + +post { + url: {{cpBaseUrl}}/api/mgmt/v5beta/participants/{{consumer_id}}/contractnegotiations + body: json + auth: inherit +} + +body:json { + { + "@context": [ + "https://w3id.org/edc/connector/management/v2" + ], + "@type": "ContractRequest", + "protocol": "dataspace-protocol-http:2025-1", + "counterPartyAddress": "http://controlplane.edc-v.svc.cluster.local:8082/api/dsp/{{provider_id}}/2025-1", + "policy": { + "@id": "{{POLICY_ID}}", + "@type": "Offer", + "target": "{{DATASET_ID}}", + "assigner": "did:web:identityhub.edc-v.svc.cluster.local%3A7083:provider", + "permission": [ + { + "action": "use", + "constraint": [ + { + "leftOperand": "MembershipCredential", + "operator": "eq", + "rightOperand": "active" + } + ] + } + ] + } + } +} + +script:post-response { + try { + const json = res.getBody(); + const negotiationId = json["@id"]; + + if (negotiationId && typeof negotiationId === 'string') { + bru.setVar('NEGOTIATION_ID', negotiationId); + console.log('NegotiationId ID (NEGOTIATION_ID) is:', negotiationId); + } else { + console.warn('Policy ID not found in response at json["@id"]'); + } + + // Optional: assertion to ensure it exists + test('NegotiationId ID is present and stored', function () { + expect(negotiationId, 'NegotiationId ID should exist').to.be.a('string').and.not.empty; + }); + + } catch (e) { + console.error('Failed to parse response or set NEGOTIATION_ID:', e); + test('Response is valid JSON', function () { + throw e; + }); + } +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Setup Transfer.bru b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Setup Transfer.bru index 9d9d476..ef82751 100644 --- a/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Setup Transfer.bru +++ b/requests/EDC-V Onboarding/EDC-V Management/Data Transfer/Http Certs/Consumer/Setup Transfer.bru @@ -1,35 +1,41 @@ meta { name: Setup Transfer type: http - seq: 2 + seq: 4 } post { - url: {{cpBaseUrl}}/api/mgmt/v1alpha/participants/{{consumer_id}}/transfer + url: {{cpBaseUrl}}/api/mgmt/v5beta/participants/{{consumer_id}}/transferprocesses body: json auth: inherit } body:json { { - "providerId":"did:web:identityhub.edc-v.svc.cluster.local%3A7083:provider", - "policyId": "{{POLICY_ID}}" + "@context": [ + "https://w3id.org/edc/connector/management/v2" + ], + "@type": "TransferRequest", + "protocol": "dataspace-protocol-http:2025-1", + "counterPartyAddress": "http://controlplane.edc-v.svc.cluster.local:8082/api/dsp/{{provider_id}}/2025-1", + "contractId": "{{AGREEMENT_ID}}", + "transferType": "HttpData-PULL" } } script:post-response { try { const json = res.getBody(); - const accessToken = json['authorization']; + const transferProcessId = json['@id']; - if (accessToken && typeof accessToken === 'string') { - bru.setVar('ACCESS_TOKEN', accessToken); + if (transferProcessId && typeof transferProcessId === 'string') { + bru.setVar('TRANSFER_ID', transferProcessId); } else { - console.warn('Access token not found'); + console.warn('Transfer Id not found'); } } catch (e) { - console.error('Failed to parse response or set Access token:', e); + console.error('Failed to parse response or set transfer id:', e); test('Response is valid JSON', function () { throw e; }); diff --git a/requests/EDC-V Onboarding/environments/KinD Local.bru b/requests/EDC-V Onboarding/environments/KinD Local.bru index 6dbae38..81d56f2 100644 --- a/requests/EDC-V Onboarding/environments/KinD Local.bru +++ b/requests/EDC-V Onboarding/environments/KinD Local.bru @@ -6,4 +6,5 @@ vars { pmBaseUrl: http://pm.localhost VAULT_TOKEN: root dpBaseUrl: http://dp.localhost + sigletBaseUrl: http://siglet.localhost } diff --git a/settings.gradle.kts b/settings.gradle.kts index 325a21c..ea4a99d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -25,7 +25,6 @@ pluginManagement { } rootProject.name = "jad" -include(":extensions:api:mgmt") include(":extensions:data-plane-certs") include(":tests:end2end") diff --git a/tests/end2end/build.gradle.kts b/tests/end2end/build.gradle.kts index 9680ba4..a1da24f 100644 --- a/tests/end2end/build.gradle.kts +++ b/tests/end2end/build.gradle.kts @@ -25,6 +25,8 @@ dependencies { testImplementation(libs.jackson.annotations) testImplementation(libs.awaitility) testImplementation(libs.restAssured) + testImplementation(testFixtures(libs.edc.fixtures.mgmtapi)) + } edcBuild { diff --git a/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/Constants.java b/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/Constants.java index b2383ac..a085c81 100644 --- a/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/Constants.java +++ b/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/Constants.java @@ -23,7 +23,9 @@ public interface Constants { String PM_BASE_URL = "http://pm.localhost:8080"; String VAULT_URL = "http://vault.localhost:8080"; String CONTROLPLANE_BASE_URL = "http://cp.localhost:8080"; + String SIGLET_BASE_URL = "http://siglet.localhost:8080"; String DATAPLANE_BASE_URL = "http://dp.localhost:8080"; String IDENTITYHUB_BASE_URL = "http://ih.localhost:8080"; String KEYCLOAK_URL = "http://keycloak.localhost:8080"; + String CONTROLPLANE_PROTOCOL_URL = "http://controlplane.edc-v.svc.cluster.local:8082/api/dsp/%s/2025-1"; } diff --git a/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/DataTransferEndToEndTest.java b/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/DataTransferEndToEndTest.java index fadf62c..971fb6d 100644 --- a/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/DataTransferEndToEndTest.java +++ b/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/DataTransferEndToEndTest.java @@ -19,27 +19,41 @@ import io.restassured.RestAssured; import io.restassured.config.ObjectMapperConfig; import io.restassured.config.RestAssuredConfig; -import org.eclipse.edc.jad.tests.model.CatalogResponse; +import org.eclipse.edc.connector.controlplane.test.system.utils.client.ManagementApiClientV5; +import org.eclipse.edc.connector.controlplane.test.system.utils.client.api.model.AssetDto; +import org.eclipse.edc.connector.controlplane.test.system.utils.client.api.model.AtomicConstraintDto; +import org.eclipse.edc.connector.controlplane.test.system.utils.client.api.model.CelExpressionDto; +import org.eclipse.edc.connector.controlplane.test.system.utils.client.api.model.ContractDefinitionDto; +import org.eclipse.edc.connector.controlplane.test.system.utils.client.api.model.CriterionDto; +import org.eclipse.edc.connector.controlplane.test.system.utils.client.api.model.DataPlaneRegistrationDto; +import org.eclipse.edc.connector.controlplane.test.system.utils.client.api.model.PermissionDto; +import org.eclipse.edc.connector.controlplane.test.system.utils.client.api.model.PolicyDefinitionDto; +import org.eclipse.edc.connector.controlplane.test.system.utils.client.api.model.PolicyDto; import org.eclipse.edc.jad.tests.model.ClientCredentials; import org.eclipse.edc.junit.annotations.EndToEndTest; +import org.eclipse.edc.junit.utils.LazySupplier; import org.eclipse.edc.spi.monitor.ConsoleMonitor; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.IOException; +import java.net.URI; import java.time.Instant; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import static io.restassured.RestAssured.given; import static org.assertj.core.api.Assertions.assertThat; import static org.eclipse.edc.jad.tests.Constants.APPLICATION_JSON; import static org.eclipse.edc.jad.tests.Constants.CONTROLPLANE_BASE_URL; +import static org.eclipse.edc.jad.tests.Constants.CONTROLPLANE_PROTOCOL_URL; import static org.eclipse.edc.jad.tests.Constants.DATAPLANE_BASE_URL; +import static org.eclipse.edc.jad.tests.Constants.SIGLET_BASE_URL; import static org.eclipse.edc.jad.tests.Constants.TM_BASE_URL; import static org.eclipse.edc.jad.tests.KeycloakApi.createKeycloakToken; import static org.eclipse.edc.jad.tests.KeycloakApi.getAccessToken; -import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; /** * This test class executes a series of REST requests against several components to verify that an end-to-end @@ -54,12 +68,13 @@ public class DataTransferEndToEndTest { private static final String VAULT_TOKEN = "root"; private static final ConsoleMonitor MONITOR = new ConsoleMonitor(ConsoleMonitor.Level.DEBUG, true); + private static final DynamicTokenProvider DYNAMIC_TOKEN_PROVIDER = new DynamicTokenProvider(); + private static final ManagementApiClientV5 MANAGEMENT_API_CLIENT = new ManagementApiClientV5(DYNAMIC_TOKEN_PROVIDER, new LazySupplier<>(() -> URI.create(CONTROLPLANE_BASE_URL + "/api/mgmt"))); private static ClientCredentials providerCredentials; private static ClientCredentials consumerCredentials; private static String providerContextId; private static ClientCredentials manufacturerCredentials; - static String loadResourceFile(String resourceName) { try (var is = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName)) { if (is == null) { @@ -82,11 +97,13 @@ static void prepare() { } )); + var slug = Instant.now().getEpochSecond(); - var adminToken = createKeycloakToken("admin", "edc-v-admin-secret", "issuer-admin-api:write", "identity-api:write", "management-api:write", "identity-api:read"); - createCelExpression(adminToken, "membership_cel_expression.json"); - createCelExpression(adminToken, "manufacturer_cel_expression.json"); + DYNAMIC_TOKEN_PROVIDER.setDefaultTokenGenerator(() -> createKeycloakToken("admin", "edc-v-admin-secret", "issuer-admin-api:write", "identity-api:write", "management-api:write", "identity-api:read")); + + createMembershipCelExpression(); + createManufacturerCelExpression(); MONITOR.info("Create cell and dataspace profile"); var cellId = getCellId(); @@ -113,23 +130,24 @@ static void prepare() { manufacturerCredentials = manufacturerPo.execute(cellId, "manufacturer"); } - /** - * Creates a Common Expression Language (CEL) entry in the control plane - * - * @param accessToken OAuth2 token - * @param resourceName name of the resource file that contains the CEL expression. - */ - private static void createCelExpression(String accessToken, String resourceName) { - var template = loadResourceFile(resourceName); + private static void createMembershipCelExpression() { + var expr = "ctx.agent.claims.vc.filter(c, c.type.exists(t, t == 'MembershipCredential')).exists(c, c.credentialSubject.exists(cs, timestamp(cs.membershipStartDate) < now))"; + var celExpression = new CelExpressionDto("MembershipCredential", + expr, + Set.of("catalog", "contract.negotiation", "transfer.process"), + "Expression for evaluating membership credential" + ); + MANAGEMENT_API_CLIENT.expressions().createExpression(celExpression); + } - given() - .baseUri(CONTROLPLANE_BASE_URL) - .auth().oauth2(accessToken) - .contentType("application/json") - .body(template) - .post("/api/mgmt/v5beta/celexpressions") - .then() - .statusCode(200); + private static void createManufacturerCelExpression() { + var expr = "ctx.agent.claims.vc.filter(c, c.type.exists(t, t == 'ManufacturerCredential')).exists(c, c.credentialSubject.exists(cs, timestamp(cs.since) < now))"; + var celExpression = new CelExpressionDto("ManufacturerCredential", + expr, + Set.of("catalog", "contract.negotiation", "transfer.process"), + "Expression for evaluating manufacturer credential" + ); + MANAGEMENT_API_CLIENT.expressions().createExpression(celExpression); } /** @@ -151,40 +169,33 @@ void testCertDataTransfer() { // seed provider MONITOR.info("Seeding provider"); - var providerAccessToken = getAccessToken(providerCredentials.clientId(), providerCredentials.clientSecret(), "management-api:write").accessToken(); - var consumerAccessToken = getAccessToken(consumerCredentials.clientId(), consumerCredentials.clientSecret(), "management-api:write").accessToken(); - var assetId = createCertAsset(providerCredentials.clientId(), providerAccessToken); - var policyDefId = createPolicyDef(providerCredentials.clientId(), providerAccessToken, "policy-def.json"); - createContractDef(providerCredentials.clientId(), providerAccessToken, policyDefId, policyDefId, assetId); + + DYNAMIC_TOKEN_PROVIDER.registerTokenGenerator(providerCredentials.clientId(), () -> getAccessToken(providerCredentials.clientId(), providerCredentials.clientSecret(), "management-api:write management-api:read").accessToken()); + DYNAMIC_TOKEN_PROVIDER.registerTokenGenerator(consumerCredentials.clientId(), () -> getAccessToken(consumerCredentials.clientId(), consumerCredentials.clientSecret(), "management-api:write management-api:read").accessToken()); + + var assetId = createCertAsset(providerCredentials.clientId()); + var policyDefId = createPolicyDef(providerCredentials.clientId(), "MembershipCredential"); + createContractDef(providerCredentials.clientId(), policyDefId, policyDefId, assetId); // Register dataplanes - registerDataPlane(providerCredentials.clientId(), providerAccessToken); - registerDataPlane(consumerCredentials.clientId(), consumerAccessToken); + registerDataPlane(providerCredentials.clientId()); + registerDataPlane(consumerCredentials.clientId()); + + MONITOR.info("starting data transfer"); + + var transferId = MANAGEMENT_API_CLIENT.startTransfer(consumerCredentials.clientId(), + providerCredentials.clientId(), CONTROLPLANE_PROTOCOL_URL.formatted(providerCredentials.clientId()), providerContextId, assetId, "HttpData-PULL"); - // perform data transfer - MONITOR.info("Starting data transfer"); - var catalog = fetchCatalog(consumerCredentials); - MONITOR.info("Catalog received, starting data transfer"); - var offerId = catalog.datasets().stream().filter(dataSet -> dataSet.id().equals(assetId)).findFirst().get().offers().get(0).id(); - assertThat(offerId).isNotNull(); + MONITOR.info("Fetching siglet token for transferId: " + transferId); - // trigger transfer var transferResponse = given() - .baseUri(CONTROLPLANE_BASE_URL) - .auth().oauth2(consumerAccessToken) - .body(""" - { - "providerId":"%s", - "policyId": "%s" - } - """.formatted(providerContextId, offerId)) - .contentType("application/json") - .post("/api/mgmt/v1alpha/participants/%s/transfer".formatted(consumerCredentials.clientId())) + .baseUri(SIGLET_BASE_URL) + .get("/tokens/%s/%s".formatted(consumerCredentials.clientId(), transferId)) .then() .statusCode(200) .extract().body().as(Map.class); - var accessToken = transferResponse.get("authorization"); + var accessToken = transferResponse.get("token"); var list = given() .baseUri(DATAPLANE_BASE_URL) @@ -203,61 +214,42 @@ void testCertDataTransfer() { void testTransferLimitedAccess() { // seed provider MONITOR.info("Seeding provider"); - var providerAccessToken = getAccessToken(providerCredentials.clientId(), providerCredentials.clientSecret(), "management-api:write").accessToken(); - var consumerAccessToken = getAccessToken(consumerCredentials.clientId(), consumerCredentials.clientSecret(), "management-api:write").accessToken(); - var manufacturerAccessToken = getAccessToken(manufacturerCredentials.clientId(), manufacturerCredentials.clientSecret(), "management-api:write").accessToken(); - var assetId = createAsset(providerCredentials.clientId(), providerAccessToken, "asset-restricted.json"); - var accessPolicyId = createPolicyDef(providerCredentials.clientId(), providerAccessToken, "policy-def.json"); - var contractPolicyId = createPolicyDef(providerCredentials.clientId(), providerAccessToken, "policy-def-manufacturer.json"); - createContractDef(providerCredentials.clientId(), providerAccessToken, accessPolicyId, contractPolicyId, assetId); - - registerDataPlane(providerCredentials.clientId(), providerAccessToken); - registerDataPlane(consumerCredentials.clientId(), consumerAccessToken); - registerDataPlane(manufacturerCredentials.clientId(), manufacturerAccessToken); - - // perform data transfer - MONITOR.info("Starting data transfer"); - var catalog = fetchCatalog(consumerCredentials); - - MONITOR.info("Catalog received, starting data transfer"); - var offerId = catalog.datasets().stream().filter(dataSet -> dataSet.id().equals(assetId)).findFirst().get().offers().get(0).id(); - assertThat(offerId).isNotNull(); - - - // attempt download as a normal consumer - should fail due to missing credentials - given() - .baseUri(CONTROLPLANE_BASE_URL) - .auth().oauth2(consumerAccessToken) - .body(""" - { - "providerId":"%s", - "policyId": "%s", - "policyType": "manufacturer" - } - """.formatted(providerContextId, offerId)) - .contentType("application/json") - .post("/api/mgmt/v1alpha/participants/%s/transfer".formatted(consumerCredentials.clientId())) - .then() - .statusCode(500); - // download the asset as manufacturer - should work because the manufacturer has the necessary credentials + DYNAMIC_TOKEN_PROVIDER.registerTokenGenerator(providerCredentials.clientId(), () -> getAccessToken(providerCredentials.clientId(), providerCredentials.clientSecret(), "management-api:write management-api:read").accessToken()); + DYNAMIC_TOKEN_PROVIDER.registerTokenGenerator(consumerCredentials.clientId(), () -> getAccessToken(consumerCredentials.clientId(), consumerCredentials.clientSecret(), "management-api:write management-api:read").accessToken()); + DYNAMIC_TOKEN_PROVIDER.registerTokenGenerator(manufacturerCredentials.clientId(), () -> getAccessToken(manufacturerCredentials.clientId(), manufacturerCredentials.clientSecret(), "management-api:write management-api:read").accessToken()); + + var assetId = createAsset(providerCredentials.clientId(), "This asset requires the Manufacturer credential to access"); + var accessPolicyId = createPolicyDef(providerCredentials.clientId(), "MembershipCredential"); + var contractPolicyId = createPolicyDef(providerCredentials.clientId(), "ManufacturerCredential"); + createContractDef(providerCredentials.clientId(), accessPolicyId, contractPolicyId, assetId); + + registerDataPlane(providerCredentials.clientId()); + registerDataPlane(consumerCredentials.clientId()); + registerDataPlane(manufacturerCredentials.clientId()); + + var negotiationId = MANAGEMENT_API_CLIENT.initContractNegotiation(consumerCredentials.clientId(), + assetId, CONTROLPLANE_PROTOCOL_URL.formatted(providerCredentials.clientId()), providerContextId); + + + MANAGEMENT_API_CLIENT.waitForContractNegotiationState(consumerCredentials.clientId(), negotiationId, "TERMINATED"); + + MONITOR.info("starting data transfer"); + + var transferId = MANAGEMENT_API_CLIENT.startTransfer(manufacturerCredentials.clientId(), + providerCredentials.clientId(), CONTROLPLANE_PROTOCOL_URL.formatted(providerCredentials.clientId()), providerContextId, assetId, "HttpData-PULL"); + + + MONITOR.info("Fetching siglet token for transferId: " + transferId); + var transferResponse = given() - .baseUri(CONTROLPLANE_BASE_URL) - .auth().oauth2(manufacturerAccessToken) - .body(""" - { - "providerId":"%s", - "policyId": "%s", - "policyType": "manufacturer" - } - """.formatted(providerContextId, offerId)) - .contentType("application/json") - .post("/api/mgmt/v1alpha/participants/%s/transfer".formatted(manufacturerCredentials.clientId())) + .baseUri(SIGLET_BASE_URL) + .get("/tokens/%s/%s".formatted(manufacturerCredentials.clientId(), transferId)) .then() .statusCode(200) .extract().body().as(Map.class); - var accessToken = transferResponse.get("authorization"); + var accessToken = transferResponse.get("token"); var list = given() .baseUri(DATAPLANE_BASE_URL) @@ -273,95 +265,43 @@ void testTransferLimitedAccess() { } - private CatalogResponse fetchCatalog(ClientCredentials consumerCredentials) { - var accessToken = getAccessToken(consumerCredentials.clientId(), consumerCredentials.clientSecret(), "management-api:read"); - - return given() - .baseUri(CONTROLPLANE_BASE_URL) - .auth().oauth2(accessToken.accessToken()) - .contentType("application/json") - .body(""" - { - "counterPartyDid": "%s" - } - """.formatted(providerContextId)) - .post("/api/mgmt/v1alpha/participants/%s/catalog".formatted(consumerCredentials.clientId())) - .then() - .statusCode(200) - .extract().body() - .as(CatalogResponse.class); - } - /** * Registers a data plane for a new participant context. This is a bit of a workaround, until Dataplane Signaling is fully implemented. * Check also the {@code DataplaneRegistrationApiController} in the {@code extensions/api/mgmt} directory * * @param participantContextId Participant context for which the data plane should be registered. - * @param accessToken OAuth2 token */ - private void registerDataPlane(String participantContextId, String accessToken) { - given() - .baseUri(CONTROLPLANE_BASE_URL) - .contentType(APPLICATION_JSON) - .auth().oauth2(accessToken) - .body(""" - { - "id": "dataplane-%s", - "transferTypes": [ "HttpData-PULL" ], - "endpoint": "http://siglet.edc-v.svc.cluster.local:8081/api/v1/%s/dataflows" - } - """.formatted(participantContextId, participantContextId)) - .put("/api/mgmt/v5beta/participants/%s/dataplanes".formatted(participantContextId)) - .then() - .log().ifValidationFails() - .statusCode(200); + private void registerDataPlane(String participantContextId) { + MANAGEMENT_API_CLIENT.dataplanes().registerDataPlane(participantContextId, new DataPlaneRegistrationDto( + "dataplane-%s".formatted(participantContextId), + "http://siglet.edc-v.svc.cluster.local:8081/api/v1/%s/dataflows".formatted(participantContextId), + Set.of("HttpData-PULL"), + Set.of(), + null + )); } - private String createAsset(String participantContextId, String accessToken, String resourceName) { - var template = loadResourceFile(resourceName); - return given() - .baseUri(CONTROLPLANE_BASE_URL) - .auth().oauth2(accessToken) - .contentType("application/json") - .body(template) - .post("/api/mgmt/v5beta/participants/%s/assets".formatted(participantContextId)) - .then() - .statusCode(200) - .extract().jsonPath().getString(ID); + private String createAsset(String participantContextId, String description) { + var properties = new HashMap(); + properties.put("description", description); + var asset = new AssetDto(properties, null); + return MANAGEMENT_API_CLIENT.assets().createAsset(participantContextId, asset); } - private String createCertAsset(String participantContextId, String accessToken) { - return createAsset(participantContextId, accessToken, "asset-cert.json"); + private String createCertAsset(String participantContextId) { + return createAsset(participantContextId, "This asset requires the Membership credential to access"); } - private String createPolicyDef(String participantContextId, String accessToken, String resourceName) { - var template = loadResourceFile(resourceName); - return given() - .baseUri(CONTROLPLANE_BASE_URL) - .auth().oauth2(accessToken) - .contentType("application/json") - .body(template) - .post("/api/mgmt/v5beta/participants/%s/policydefinitions".formatted(participantContextId)) - .then() - .statusCode(200) - .extract().jsonPath().getString(ID); + private String createPolicyDef(String participantContextId, String leftOperand) { + var constraint = new AtomicConstraintDto(leftOperand, "eq", "active"); + var permission = new PermissionDto(constraint); + var policy = new PolicyDto(List.of(permission)); + return MANAGEMENT_API_CLIENT.policies().createPolicyDefinition(participantContextId, new PolicyDefinitionDto(policy)); } - private String createContractDef(String participantContextId, String accessToken, String accessPolicyId, String contractPolicyId, String assetId) { - var template = loadResourceFile("contract-def.json"); - - template = template.replace("{{access_policy_id}}", accessPolicyId); - template = template.replace("{{contract_policy_id}}", contractPolicyId); - template = template.replace("{{asset_id}}", assetId); - - return given() - .baseUri(CONTROLPLANE_BASE_URL) - .auth().oauth2(accessToken) - .contentType("application/json") - .body(template) - .post("/api/mgmt/v5beta/participants/%s/contractdefinitions".formatted(participantContextId)) - .then() - .statusCode(200) - .extract().jsonPath().getString(ID); + private String createContractDef(String participantContextId, String accessPolicyId, String contractPolicyId, String assetId) { + var selector = new CriterionDto("https://w3id.org/edc/v0.0.1/ns/id", "=", assetId); + var contractDef = new ContractDefinitionDto(accessPolicyId, contractPolicyId, List.of(selector)); + return MANAGEMENT_API_CLIENT.contractDefinitions().createContractDefinition(participantContextId, contractDef); } } diff --git a/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/DynamicTokenProvider.java b/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/DynamicTokenProvider.java new file mode 100644 index 0000000..7c9d7e9 --- /dev/null +++ b/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/DynamicTokenProvider.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2026 Metaform Systems, Inc. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Metaform Systems, Inc. - initial API and implementation + * + */ + +package org.eclipse.edc.jad.tests; + +import org.eclipse.edc.api.authentication.OauthTokenProvider; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +public class DynamicTokenProvider implements OauthTokenProvider { + + private final Map> tokenGenerators = new ConcurrentHashMap<>(); + public Supplier defaultTokenGenerator; + + @Override + public String createToken(String participantContextId, String role) { + if (participantContextId == null) { + if (defaultTokenGenerator == null) { + throw new IllegalStateException("No default token generator registered"); + } + return defaultTokenGenerator.get(); + } else { + return Objects.requireNonNull(tokenGenerators.get(participantContextId)).get(); + } + } + + public void registerTokenGenerator(String participantContextId, Supplier tokenGenerator) { + tokenGenerators.put(participantContextId, tokenGenerator); + } + + public void setDefaultTokenGenerator(Supplier defaultTokenGenerator) { + this.defaultTokenGenerator = defaultTokenGenerator; + } +} diff --git a/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/model/CatalogResponse.java b/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/model/CatalogResponse.java deleted file mode 100644 index 1693605..0000000 --- a/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/model/CatalogResponse.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2025 Metaform Systems, Inc. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Metaform Systems, Inc. - initial API and implementation - * - */ - -package org.eclipse.edc.jad.tests.model; - - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -/** - * This is a minimal version of an EDC Catalog, ignoring most unneeded fields - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public record CatalogResponse(@JsonProperty("@id") String id, - @JsonProperty("@type") String type, - @JsonProperty(value = "dataset", defaultValue = "[]") List datasets) { - -} diff --git a/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/model/DataSet.java b/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/model/DataSet.java deleted file mode 100644 index 69ae8bc..0000000 --- a/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/model/DataSet.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2025 Metaform Systems, Inc. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Metaform Systems, Inc. - initial API and implementation - * - */ - -package org.eclipse.edc.jad.tests.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record DataSet(@JsonProperty("@id") String id, @JsonProperty("hasPolicy") List offers) { - -} - - diff --git a/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/model/Offer.java b/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/model/Offer.java deleted file mode 100644 index 701dc2e..0000000 --- a/tests/end2end/src/test/java/org/eclipse/edc/jad/tests/model/Offer.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2025 Metaform Systems, Inc. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Metaform Systems, Inc. - initial API and implementation - * - */ - -package org.eclipse.edc.jad.tests.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record Offer(@JsonProperty("@id") String id) { -} \ No newline at end of file diff --git a/tests/end2end/src/test/resources/asset-cert.json b/tests/end2end/src/test/resources/asset-cert.json deleted file mode 100644 index da19337..0000000 --- a/tests/end2end/src/test/resources/asset-cert.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "@context": [ - "https://w3id.org/edc/connector/management/v2" - ], - "@type": "Asset", - "properties": { - "description": "This asset requires the Membership credential to access" - } -} \ No newline at end of file diff --git a/tests/end2end/src/test/resources/asset-restricted.json b/tests/end2end/src/test/resources/asset-restricted.json deleted file mode 100644 index f085ca6..0000000 --- a/tests/end2end/src/test/resources/asset-restricted.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "@context": [ - "https://w3id.org/edc/connector/management/v2" - ], - "@type": "Asset", - "properties": { - "description": "This asset requires the Manufacturer credential to access" - } -} \ No newline at end of file diff --git a/tests/end2end/src/test/resources/asset.json b/tests/end2end/src/test/resources/asset.json deleted file mode 100644 index da19337..0000000 --- a/tests/end2end/src/test/resources/asset.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "@context": [ - "https://w3id.org/edc/connector/management/v2" - ], - "@type": "Asset", - "properties": { - "description": "This asset requires the Membership credential to access" - } -} \ No newline at end of file diff --git a/tests/end2end/src/test/resources/contract-def.json b/tests/end2end/src/test/resources/contract-def.json deleted file mode 100644 index f552b79..0000000 --- a/tests/end2end/src/test/resources/contract-def.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "@context": [ - "https://w3id.org/edc/connector/management/v2" - ], - "@type": "ContractDefinition", - "accessPolicyId": "{{access_policy_id}}", - "contractPolicyId": "{{contract_policy_id}}", - "assetsSelector": [ - { - "@type": "Criterion", - "operandLeft": "https://w3id.org/edc/v0.0.1/ns/id", - "operator": "=", - "operandRight": "{{asset_id}}" - } - ] -} \ No newline at end of file diff --git a/tests/end2end/src/test/resources/manufacturer_cel_expression.json b/tests/end2end/src/test/resources/manufacturer_cel_expression.json deleted file mode 100644 index a2e2d0c..0000000 --- a/tests/end2end/src/test/resources/manufacturer_cel_expression.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "@context": [ - "https://w3id.org/edc/connector/management/v2" - ], - "@type": "CelExpression", - "leftOperand": "ManufacturerCredential", - "description": "Expression for evaluating manufacturer credentials", - "scopes": [ - "catalog", - "contract.negotiation", - "transfer.process" - ], - "expression": "ctx.agent.claims.vc.filter(c, c.type.exists(t, t == 'ManufacturerCredential')).exists(c, c.credentialSubject.exists(cs, timestamp(cs.since) < now))" -} \ No newline at end of file diff --git a/tests/end2end/src/test/resources/membership_cel_expression.json b/tests/end2end/src/test/resources/membership_cel_expression.json deleted file mode 100644 index 8d2937f..0000000 --- a/tests/end2end/src/test/resources/membership_cel_expression.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "@context": [ - "https://w3id.org/edc/connector/management/v2" - ], - "@type": "CelExpression", - "leftOperand": "MembershipCredential", - "description": "Expression for evaluating membership credential", - "scopes": [ - "catalog", - "contract.negotiation", - "transfer.process" - ], - "expression": "ctx.agent.claims.vc.filter(c, c.type.exists(t, t == 'MembershipCredential')).exists(c, c.credentialSubject.exists(cs, timestamp(cs.membershipStartDate) < now))" -} \ No newline at end of file diff --git a/tests/end2end/src/test/resources/policy-def-manufacturer.json b/tests/end2end/src/test/resources/policy-def-manufacturer.json deleted file mode 100644 index fd68935..0000000 --- a/tests/end2end/src/test/resources/policy-def-manufacturer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "@context": [ - "https://w3id.org/edc/connector/management/v2" - ], - "@type": "PolicyDefinition", - "policy": { - "@type": "Set", - "permission": [ - { - "action": "use", - "constraint": [ - { - "leftOperand": "ManufacturerCredential", - "operator": "eq", - "rightOperand": "active" - } - ] - } - ] - } -} \ No newline at end of file diff --git a/tests/end2end/src/test/resources/policy-def.json b/tests/end2end/src/test/resources/policy-def.json deleted file mode 100644 index c46bbeb..0000000 --- a/tests/end2end/src/test/resources/policy-def.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "@context": [ - "https://w3id.org/edc/connector/management/v2" - ], - "@type": "PolicyDefinition", - "policy": { - "@type": "Set", - "permission": [ - { - "action": "use", - "constraint": [ - { - "leftOperand": "MembershipCredential", - "operator": "eq", - "rightOperand": "active" - } - ] - } - ] - } -} \ No newline at end of file