From 12dd778c89ff6a2d91d05fd1079b1b8c2123ac25 Mon Sep 17 00:00:00 2001 From: David Winslow Date: Mon, 4 Nov 2024 10:35:51 +0100 Subject: [PATCH 01/26] feat: Adding oidc implementation for service connections. --- README.md | 617 ++++++++++++++++++----------- images/oidc-integration.png | Bin 0 -> 52369 bytes images/oidc-json-mapping.png | Bin 0 -> 12759 bytes images/oidc-service-connection.png | Bin 0 -> 106061 bytes jfrog-tasks-utils/package.json | 3 +- jfrog-tasks-utils/utils.js | 77 +++- vss-extension.json | 132 +++++- 7 files changed, 596 insertions(+), 233 deletions(-) create mode 100644 images/oidc-integration.png create mode 100644 images/oidc-json-mapping.png create mode 100644 images/oidc-service-connection.png diff --git a/README.md b/README.md index 597c2163..58fe04e5 100644 --- a/README.md +++ b/README.md @@ -13,120 +13,147 @@ # Overview -[JFrog](https://jfrog.com/) provides tight integration with [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) through the *[JFrog Extension](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension)* +[JFrog](https://jfrog.com/) provides tight integration with [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) through the _[JFrog Extension](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension)_ Beyond managing efficient deployment of your artifacts to [JFrog Artifactory](https://jfrog.com/artifactory), the extension lets you capture information about artifacts deployed, dependencies resolved, environment data associated with the build runs and more, that effectively facilitates fully traceable builds. -JFrog brings continuous integration to [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) through the *JFrog* extension. +JFrog brings continuous integration to [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) through the _JFrog_ extension. -The *[JFrog Extension](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension)* for Azure DevOps supports: - -* Running your builds while using [JFrog Artifactory](https://jfrog.com/artifactory) as the binary repository manager. -* Gaining full traceability of your builds by capturing your build-info from your builds and publishing it to [JFrog Artifactory](https://jfrog.com/artifactory). -* Managing your binaries lifecycle with [JFrog Artifactory](https://jfrog.com/artifactory). -* Auditing your projects and scanning your builds with [JFrog Xray](https://jfrog.com/xray). -* Distributing your artifacts with [JFrog Distribution](https://jfrog.com/distribution/). +The _[JFrog Extension](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension)_ for Azure DevOps supports: +- Running your builds while using [JFrog Artifactory](https://jfrog.com/artifactory) as the binary repository manager. +- Gaining full traceability of your builds by capturing your build-info from your builds and publishing it to [JFrog Artifactory](https://jfrog.com/artifactory). +- Managing your binaries lifecycle with [JFrog Artifactory](https://jfrog.com/artifactory). +- Auditing your projects and scanning your builds with [JFrog Xray](https://jfrog.com/xray). +- Distributing your artifacts with [JFrog Distribution](https://jfrog.com/distribution/). ## Table of contents -- [Table of contents](#Table-of-contents) - - [Overview](#Overview) - - [Download and Installation](#Download-and-Installation) - - [Installing the Extension](#Installing-the-Extension) - - [Installing the Build Agent](#Installing-the-Build-Agent) - - [Configuring the Service Connections](#Configuring-the-Service-Connections) - - [Executing JFrog CLI Commands](#Executing-JFrog-CLI-Commands) - - [Build tools Tasks](#build-tools-tasks) - - [JFrog Maven](#JFrog-Maven-Task) - - [JFrog Gradle](#JFrog-Gradle-Task) - - [JFrog Npm](#JFrog-Npm-Task) - - [JFrog Nuget](#JFrog-Nuget-and-NET-Core-Task) - - [JFrog .NET Core](#JFrog-Nuget-and-NET-Core-Task) - - [JFrog Pip](#JFrog-Pip-Task) - - [JFrog Conan](#JFrog-Conan-Task) - - [JFrog Go](#JFrog-Go-Task) - - [Build Tasks](#Build-tasks) - - [JFrog Collect Build Issues](#JFrog-Collect-Build-Issues) - - [JFrog Publish Build Info](#JFrog-Publish-Build-Info) - - [JFrog Build Promotion](#JFrog-Build-Promotion) - - [Discarding Published Builds](#Discarding-Published-Builds-from-Artifactory) - - [Managing Generic Artifacts](#Managing-Generic-Artifacts) - - [JFrog Xray](#JFrog-Xray-tasks) - - [Audit project's dependencies for Security Vulnerabilities](#Audit-projects-dependencies-for-Security-Vulnerabilities) - - [Scanning Published Builds for Security Vulnerabilities with JFrog Xray](#Scanning-Published-Builds-for-Security-Vulnerabilities) - - [JFrog Docker Tasks](#JFrog-Docker-tasks) - - [Pushing and Pulling Docker Images to and from Artifactory](#Pushing-and-Pulling-Docker-Images-to-and-from-Artifactory) - - [Scanning Local Docker Images with JFrog Xray](#Scanning-Local-Docker-Images-with-JFrog-Xray) - - [JFrog Distribution](#Managing-and-Distributing-Release-Bundles) - - [JFrog Distribution Task](#JFrog-Distribution-V2-Task) - - [Contributions](#Contribution) +- [JFrog Azure DevOps Extension](#jfrog-azure-devops-extension) +- [Overview](#overview) + - [Table of contents](#table-of-contents) + - [Download and Installation](#download-and-installation) + - [Installing the Extension](#installing-the-extension) + - [Installing the Build Agent](#installing-the-build-agent) + - [Automatic Installation](#automatic-installation) + - [Custom tools Installation](#custom-tools-installation) + - [Manual Installation](#manual-installation) + - [Installing JFrog CLI](#installing-jfrog-cli) + - [Installing the Maven Extractor](#installing-the-maven-extractor) + - [Installing the Gradle Extractor](#installing-the-gradle-extractor) + - [Installing Conan](#installing-conan) + - [Using TFS 2015](#using-tfs-2015) + - [Configuring the Service Connections](#configuring-the-service-connections) + - [Using OpenID Connect (OIDC) Authentication](#using-openid-connect-oidc-authentication) + - [Configure OpenID Connect Integration](#configure-openid-connect-integration) + - [Configure Identity Mappings](#configure-identity-mappings) + - [Configure the Service Connection](#configure-the-service-connection) + - [Executing JFrog CLI Commands](#executing-jfrog-cli-commands) + - [JFrog CLI V2 Task](#jfrog-cli-v2-task) + - [Managing Generic Artifacts](#managing-generic-artifacts) + - [Generic artifacts handling](#generic-artifacts-handling) + - [Downloading generic build dependencies from Artifactory](#downloading-generic-build-dependencies-from-artifactory) + - [Uploading generic build artifacts to Artifactory](#uploading-generic-build-artifacts-to-artifactory) + - [Setting / Deleting properties on files in Artifactory](#setting--deleting-properties-on-files-in-artifactory) + - [Moving / Copying / Deleting artifacts in Artifactory](#moving--copying--deleting-artifacts-in-artifactory) + - [Build tools Tasks](#build-tools-tasks) + - [JFrog Maven Task](#jfrog-maven-task) + - [JFrog Gradle Task](#jfrog-gradle-task) + - [JFrog Npm Task](#jfrog-npm-task) + - [JFrog Nuget and .NET Core Task](#jfrog-nuget-and-net-core-task) + - [JFrog Pip Task](#jfrog-pip-task) + - [JFrog Conan Task](#jfrog-conan-task) + - [JFrog Go Task](#jfrog-go-task) + - [Build Tasks](#build-tasks) + - [JFrog Collect Build Issues](#jfrog-collect-build-issues) + - [Configuration properties](#configuration-properties) + - [JFrog Publish Build Info](#jfrog-publish-build-info) + - [JFrog Build Promotion](#jfrog-build-promotion) + - [Using Build Promotion in a Release](#using-build-promotion-in-a-release) + - [Discarding Published Builds from Artifactory](#discarding-published-builds-from-artifactory) + - [JFrog Xray tasks](#jfrog-xray-tasks) + - [Audit project's dependencies for Security Vulnerabilities](#audit-projects-dependencies-for-security-vulnerabilities) + - [Scanning Published Builds for Security Vulnerabilities](#scanning-published-builds-for-security-vulnerabilities) + - [JFrog Docker tasks](#jfrog-docker-tasks) + - [Pushing and Pulling Docker Images to and from Artifactory](#pushing-and-pulling-docker-images-to-and-from-artifactory) + - [Scanning Local Docker Images with JFrog Xray](#scanning-local-docker-images-with-jfrog-xray) + - [Using Published Artifacts in a Release](#using-published-artifacts-in-a-release) + - [Using JFrog Generic Artifacts task](#using-jfrog-generic-artifacts-task) + - [Using Azure Artifact source](#using-azure-artifact-source) + - [Managing and Distributing Release Bundles](#managing-and-distributing-release-bundles) + - [JFrog Distribution V2 Task](#jfrog-distribution-v2-task) + - [Contribution](#contribution) + - [Building](#building) + - [Testing](#testing) + - [Skipping Tests](#skipping-tests) + - [Reporting issues](#reporting-issues) ## Download and Installation ### Installing the Extension -To install the *[JFrog Extension](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension)*, execute the following steps: +To install the _[JFrog Extension](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension)_, execute the following steps: -* Go to - the [Visual Studio Marketplace Jfrog Extension Page](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension) - and sign in to your account. +- Go to + the [Visual Studio Marketplace Jfrog Extension Page](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension) + and sign in to your account. - - -* Click on *Get It Free* + - - -* Select the account to which you want to apply the extension and confirm installation. +- Click on _Get It Free_ -* In the JFrog Extension page, click *Install*. + - +- Select the account to which you want to apply the extension and confirm installation. +- In the JFrog Extension page, click _Install_. + ### Installing the Build Agent To run the JFrog tasks, the build agents use three tools: -* JFrog CLI: Runs all the JFrog tasks. -* Maven Extractor (Used by the [JFrog Maven](#jfrog-maven-task) task) -* Gradle Extractor (Used by the [JFrog Gradle](#jfrog-gradle-Task) task) -* Conan client (Used by the [JFrog Conan](#jfrog-conan-task) task) +- JFrog CLI: Runs all the JFrog tasks. +- Maven Extractor (Used by the [JFrog Maven](#jfrog-maven-task) task) +- Gradle Extractor (Used by the [JFrog Gradle](#jfrog-gradle-task) task) +- Conan client (Used by the [JFrog Conan](#jfrog-conan-task) task)
#### Automatic Installation + If the build agent has access to the internet, JFrog CLI along with the Maven and Gradle Extractors are downloaded and installed automatically on the agent, the first time they are required. +
#### Custom tools Installation + You can configure the pipeline to download JFrog CLI and the Maven Extractor from a JFrog Artifactory instance, which is configured to proxy the download repositories. -* Create two remote repositories in Artifactory: -* Create a remote repository in Artifactory for downloading *JFrog CLI*. Name the repository *jfrog-cli-remote* and - set its URL - to [https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf/](https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf/) -* Create a remote repository in Artifactory for downloading the *Maven and Gradle Extractors*. Name the URL *extractors* and set its URL - to: [https://releases.jfrog.io/artifactory/oss-release-local/](https://releases.jfrog.io/artifactory/oss-release-local/) -* Make sure to configure the Artifactory server with the *jfrog-cli-remote* and *extractors* repositories in as a - [service connection](#Configuring-the-Service-Connections) in Azure DevOps of type *JFrog Artifactory V2*. -* Add the *JFrog Tools Installer* task to your build or release pipeline. -* Select the Artifactory service you configured. -* Select *jfrog-cli-remote* as the target repository to download the JFrog CLI. -* If your pipeline uses the [JFrog Maven](#jfrog-maven-task) or [JFrog Gradle](#jfrog-Gradle-task) tasks, select *extractors* as the repository to - download the Maven Extractor. +- Create two remote repositories in Artifactory: +- Create a remote repository in Artifactory for downloading _JFrog CLI_. Name the repository _jfrog-cli-remote_ and + set its URL + to [https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf/](https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf/) +- Create a remote repository in Artifactory for downloading the _Maven and Gradle Extractors_. Name the URL _extractors_ and set its URL + to: [https://releases.jfrog.io/artifactory/oss-release-local/](https://releases.jfrog.io/artifactory/oss-release-local/) +- Make sure to configure the Artifactory server with the _jfrog-cli-remote_ and _extractors_ repositories in as a + [service connection](#configuring-the-service-connections) in Azure DevOps of type _JFrog Artifactory V2_. +- Add the _JFrog Tools Installer_ task to your build or release pipeline. +- Select the Artifactory service you configured. +- Select _jfrog-cli-remote_ as the target repository to download the JFrog CLI. +- If your pipeline uses the [JFrog Maven](#jfrog-maven-task) or [JFrog Gradle](#jfrog-gradle-task) tasks, select _extractors_ as the repository to + download the Maven Extractor. ![tool-installer.png](images/tool-installer.png) @@ -145,6 +172,7 @@ configured to proxy the download repositories. #### Manual Installation + ##### Installing JFrog CLI @@ -158,9 +186,9 @@ To install JFrog CLI on an agent with no internet access: 1. Create the directory structure on your agent's `file-system: $(Agent.ToolsDirectory)/_jf/current/` 2. Download the latest JFrog CLI version from [here](https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf/). -3. Please make sure to download the executable matching your agent's operating system. Make sure to download the *jf* - executable of JFrog CLI and not the legacy *jfrog* executable. -4. Copy the downloaded *jf* executable to the *current* directory you created. +3. Please make sure to download the executable matching your agent's operating system. Make sure to download the _jf_ + executable of JFrog CLI and not the legacy _jfrog_ executable. +4. Copy the downloaded _jf_ executable to the _current_ directory you created. ##### Installing the Maven Extractor @@ -212,12 +240,12 @@ The build agent requires using Node.JS version 8 and above. To check which versi agent: 1. Navigate to the `Worker\Handlers\Node` folder located under the Agent home. -2. From the terminal, run *node -v* +2. From the terminal, run _node -v_ To upgrade Node.JS on the build agent: -* Replace the existing node.exe file on the agent with the node.exe file with the required version located in - the `Worker\Handlers\Node` folder under the agent home. +- Replace the existing node.exe file on the agent with the node.exe file with the required version located in + the `Worker\Handlers\Node` folder under the agent home.
@@ -226,13 +254,12 @@ To upgrade Node.JS on the build agent: To allow the JFrog tasks to work with your JFrog environment, you'll need to configure the following service connections in Azure DevOps. -| Service connection | Used by tasks | -|:-----------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| | JFrog CLI V2 | -| | JFrog Tools Installer
JFrog Generic Artifacts
JFrog Nuget
JFrog .NET Core
JFrog npm
JFrog Pip
JFrog Maven
JFrog Gradle
JFrog Go
JFrog Conan
JFrog Collect Build Issues
JFrog Discard Builds
JFrog Build Promotion
JFrog Publish Build Info | -| | JFrog Audit
JFrog Build Scan | -| | JFrog Distribution | - +| Service connection | Used by tasks | +| :---------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| | JFrog CLI V2 | +| | JFrog Tools Installer
JFrog Generic Artifacts
JFrog Nuget
JFrog .NET Core
JFrog npm
JFrog Pip
JFrog Maven
JFrog Gradle
JFrog Go
JFrog Conan
JFrog Collect Build Issues
JFrog Discard Builds
JFrog Build Promotion
JFrog Publish Build Info | +| | JFrog Audit
JFrog Build Scan | +| | JFrog Distribution |
Not Using a Public CA (Certificate Authority)? @@ -246,6 +273,7 @@ is under JFrog CLI's home directory. The home directory default location is `$(Agent.ToolsDirectory)/_jf/` Read more about this in the [JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli). +
@@ -263,20 +291,146 @@ To enable TLS 1.2 on TFS:
-
+## Using OpenID Connect (OIDC) Authentication + +Using OpenID Connect (OIDC) to authenticate your pipelines eliminates the need for long lived static credentials providing a whole range of [security and practical benefits](https://jfrog.com/help/r/jfrog-platform-administration-documentation/openid-connect-integration-benefits). +You can read more about the [JFrog OpenID Connection Integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/openid-connect-integration) in the documentation. + +Setting up OpenID Connect has 3 separate parts: +- Setting up an OpenID Connect Integration inside of the JFrog Platform. +- Configuring Identity Mappings with Claim rules, matching to Projects & Service Connections. +- Configuring Service Connections as OpenID Connect in the Projects in your Azure Devops Instance. + +Follow the guides below to configure each part. + +
+ + +#### Configure OpenID Connect Integration + + + + +First you must configure your JFrog instance to have an OpenID Connect integration to your Azure DevOps server. +Login to your JFrog instance as an Administrator, then as [described in the documentation:](https://jfrog.com/help/r/jfrog-platform-administration-documentation/openid-connect-configurations-overview) + +1. Go to the Administrator panel. +2. Select General Management. +3. Choose Manage Integrations. +4. Select New Integration - OpenID Connect + +Now fill out the integration with the parameters of your Azure DevOps instance. + +| Property name | Description | +| ------------- | --------------------------------------------------------------------------------------- | +| Provider Name | A name for your provider, this name is used in the Azure DevOps tasks in the pipelines. | +| Provider Type | Must be set to `Generic OpenID Connect` | +| Description | A description of what this provider is for. | +| Provider URL | `https://vstoken.dev.azure.com/{ORG_GUID}` (see how to get the {ORG_GUID} below). | +| Audience | Must be set to `api://AzureADTokenExchange`. | +| Token Issuer | If the issuer is different from the provider, for Azure DevOps this can be left blank. | + +As an example the final integration configuration will look like: + +![oidc-integration.png](images/oidc-integration.png) + +In order to obtain your Azure DevOps Organization GUID (`{ORG_GUID}`) you can simply run a pipeline in your Azure DevOps organization using any of the JFrog Task setup using a Service Connection configured with the `OpenID Connect Integration` authentication method, see the [Configure the Service Connection](#configure-the-service-connection) section. Even if the task fails due to you not yet having configured the Integration in JFrog, it will output the relevant information as part of the pipeline. + +In the Pipeline Output, look for the `OIDC Token Issuer`, this value is what you must put in as your `Provider URL`. +The rest of the information can also be helpful for you to configure the Identity Mappings as described in the section below. + +``` +OIDC Token Subject: sc://// +OIDC Token Claims: {"sub": "sc:////"} +OIDC Token Issuer: https://vstoken.dev.azure.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +OIDC Token Audience: api://AzureADTokenExchange +``` +
+ +
+ + +#### Configure Identity Mappings + + + +When the `OpenID Connect Integration` has been configured, you must now configure `Identity Mappings` for your projects and service connections to allow them to utilize the integration. +You can find the full documentation for configuring [Identity Mappings in the Documentation](https://jfrog.com/help/r/jfrog-platform-administration-documentation/identity-mappings). +For this part we will focus on how to setup the JSON Claim which is used to map the JWT request of the pipeline to the access rights in your mapping. + +When working with OpenID Connect, we must look at the `ID Token` that our provider (Azure DevOps) outputs. +Based on the information in the token, we can map properties into rules in our `Identity Mappings` JSON Claim. +The `ID Token` from the Azure DevOps token provider looks like this: + +```json +{ + "jti": "", + "sub": "sc:////", + "aud": "api://AzureADTokenExchange", + "iss": "https://vstoken.dev.azure.com/", + "nbf": 1708639268, + "exp": 1708640467, + "iat": 1708639868 +} +``` +Relative to most other `ID Token` providers, our options are fairly sparse, the only sensible option is using the subject (`"sub"`) field. +The claim mapping does support wildcards with the `*` operator. + +A sample JSON Claim mapping which maps a specified ServiceConnection in a specified Project in your Organization would look like this: + +```json +{ "sub": "sc://MyOrg/MyProject/MyServiceConnection" } +``` +![oidc-json-mapping.png](images/oidc-json-mapping.png) + +To allow all projects in your Organization with a ServiceConnection with a specified name, you could replace MyProject with `*`. +Just make sure to never replace your Organization name with a `*` operator as that would allow any Azure DevOps Organization to gain access to your instance. + +
+ +
+ + +#### Configure the Service Connection + + + +You must configure a `ServiceConnection` setting the `Authentication method` to `OpenID Connect Integration`. +All four types of Service Connections are supported, they will all require the same input regardless of the type. + +This requires you to fill in the following inputs: + +| Property name | Description | +| ---------------------------- | ------------------------------------------------------------------------------------------------------ | +| Server URL | The URL of your JFrog instance with the `/artifactory` path fx. (`https://repo.jfrog.org/artifactory`) | +| OpenID Connect Provider Name | The `Provider Name` you configured in the `Configure OpenID Connect Integration` step | +| Platform URL | The URL of your JFrog instance fx. (`https://repo.jfrog.org/`) | +| Service connection name | The name of the Service Connection, must match the values put into the `JSON Claims mapping` | +| Description (optional) | A short of the purpose of this ServiceConnection | + +A sample configuration would look like this: + +![oidc-service-connection.png](images/oidc-service-connection.png) + +Now this Service Connection can be used for any of JFrog tasks as normal, authenticating with a temporary access token each time the pipeline runs. + +
+ + ## Executing JFrog CLI Commands
#### JFrog CLI V2 Task + -The extension support a generic [JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli) task, named *JFrog CLI V2*, -which allows executing *[JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli)* commands. -The command will use the connection details provided by the selected *JFrog Platform* service connection configured in +The extension support a generic [JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli) task, named _JFrog CLI V2_, +which allows executing _[JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli)_ commands. +The command will use the connection details provided by the selected _JFrog Platform_ service connection configured in Azure DevOps, so there's no need to provide the connection details as command options. @@ -293,8 +447,8 @@ Single command example: inputs: jfrogPlatformConnection: 'JFrog Platform V2' command: | - jf go-config --repo-resolve=go-remote --repo-deploy=go-local - jf go build + jf go-config --repo-resolve=go-remote --repo-deploy=go-local + jf go build jf go-publish v1.0.0 jf rt bce $(Build.DefinitionName) $(Build.BuildNumber) jf rt build-publish $(Build.DefinitionName) $(Build.BuildNumber) @@ -308,13 +462,12 @@ Multiple commands example: jfrogPlatformConnection: 'JFrog Platform V2' command: | jf rt ping - jf terraform-config --repo-deploy=terraform-remote + jf terraform-config --repo-deploy=terraform-remote jf terraform publish --namespace=example --provider=aws --tag=v0.0.1 ```
-
## Managing Generic Artifacts @@ -322,24 +475,24 @@ Multiple commands example:
JFrog Generic Artifacts task -The *JFrog Generic Artifacts* task supports following operations with JFrog Artifactory: +The _JFrog Generic Artifacts_ task supports following operations with JFrog Artifactory: -* Uploading artifacts to Artifactory -* Downloading artifacts from Artifactory -* Copying artifacts in Artifactory -* Moving artifacts in Artifactory -* Deleting artifacts in Artifactory -* Setting properties on artifacts in Artifactory -* Deleting properties from artifacts in Artifactory +- Uploading artifacts to Artifactory +- Downloading artifacts from Artifactory +- Copying artifacts in Artifactory +- Moving artifacts in Artifactory +- Deleting artifacts in Artifactory +- Setting properties on artifacts in Artifactory +- Deleting properties from artifacts in Artifactory The task triggers [JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli) to perform these actions using [File Specs](https://jfrog.com/help/r/jfrog-integrations-documentation/using-file-specs). When the task is used for uploading and downloading artifacts, it can also be configured to capture the build-info, -which can be later published to Artifactory using the *JFrog Publish Build Info* task. +which can be later published to Artifactory using the _JFrog Publish Build Info_ task. When configuring the task, do the following: -1. Select your configured *JFrog Artifactory V2* service connection. +1. Select your configured _JFrog Artifactory V2_ service connection. 2. Specify whether you'd like define the File Spec through the task UI or have the task read the spec from a file. @@ -347,11 +500,11 @@ When configuring the task, do the following: 4. Set the other task options. -5. Check the *Advanced* section for additional options. +5. Check the _Advanced_ section for additional options. ### Generic artifacts handling -The *JFrog Generic Artifacts* task allows performing generic actions on artifacts, such as: +The _JFrog Generic Artifacts_ task allows performing generic actions on artifacts, such as: 1. Downloading and uploading from/to Artifactory 2. Setting or deleting properties on artifacts in Artifactory @@ -364,7 +517,7 @@ The downloaded dependencies are defined using [File Specs](https://jfrog.com/help/r/jfrog-integrations-documentation/using-file-specs) and can be also configured to capture the build-info. It will store the downloaded files as dependencies in the build-info which can later be published to Artifactory using -the *JFrog Publish Build-Info* task. +the _JFrog Publish Build-Info_ task. ![GenericDownload](images/marketplace/generic-download.png) @@ -374,7 +527,7 @@ The task also supports uploading your generated build artifacts from the build a The artifacts are defined using [File Specs](https://jfrog.com/help/r/jfrog-integrations-documentation/using-file-specs). The task can be also configured to capture build-info and stores the uploaded files as artifacts in the build-info. The -captured build-info can be later published to Artifactory using the *JFrog Publish Build-Info* task. +captured build-info can be later published to Artifactory using the _JFrog Publish Build-Info_ task. ![GenericUpload](images/marketplace/generic-upload.png) @@ -417,26 +570,25 @@ YAML Example:
-
## Build tools Tasks -
- + #### JFrog Maven Task + ![mvn.png](images/marketplace/mvn.png) -The *JFrog Maven* task allows triggering Maven builds, while resolving dependencies and deploying artifacts from and +The _JFrog Maven_ task allows triggering Maven builds, while resolving dependencies and deploying artifacts from and to Artifactory. -The task uses the configured *JFrog Artifactory V2* service connection. +The task uses the configured _JFrog Artifactory V2_ service connection. The task can also be configured to capture build-info and store the downloaded and uploaded artifacts as build dependencies and build artifacts. -The captured build-info can be later published to Artifactory using the *[JFrog Publish Build-Info](#JFrog-Publish-Build-Info)* task. +The captured build-info can be later published to Artifactory using the _[JFrog Publish Build-Info](#jfrog-publish-build-info)_ task. ![mvn.png](images/maven-task.png) @@ -468,33 +620,35 @@ The patterns can include wildcards and should be separated by a comma followed b For more information about Maven repositories, see [Artifactory Maven Repository](https://jfrog.com/help/r/jfrog-artifactory-documentation/maven-repository) +
- + #### JFrog Gradle Task + ![gradle.png](images/marketplace/gradle.png) -The *JFrog Gradle* task allows triggering Gradle builds, while resolving dependencies and deploying artifacts from and +The _JFrog Gradle_ task allows triggering Gradle builds, while resolving dependencies and deploying artifacts from and to Artifactory. -The task uses the configured *JFrog Artifactory V2* service connection. +The task uses the configured _JFrog Artifactory V2_ service connection. The task can also be configured to capture build-info and store the downloaded and uploaded artifacts as build dependencies and build artifacts. -The captured build-info can be later published to Artifactory using the *[JFrog Publish Build-Info](#JFrog-Publish-Build-Info)* task. +The captured build-info can be later published to Artifactory using the _[JFrog Publish Build-Info](#jfrog-publish-build-info)_ task. -Behind the scenes, the *JFrog Gradle* task uses +Behind the scenes, the _JFrog Gradle_ task uses the [Gradle Artifactory Plugin](https://jfrog.com/help/r/jfrog-integrations-documentation/gradle-artifactory-plugin) to integrate with the Gradle build. In case your Gradle script already applies the [Gradle Artifactory Plugin](https://jfrog.com/help/r/jfrog-integrations-documentation/gradle-artifactory-plugin), -set the *Use Artifactory Plugin* option, to let the task know that it shouldn't apply the plugin in the Gradle script. +set the _Use Artifactory Plugin_ option, to let the task know that it shouldn't apply the plugin in the Gradle script. -You should set *artifactoryPublish* as one of the Gradle tasks in the task(s) fields. -*artifactoryPublish* is a task that is exposed by the Gradle Artifactory Plugin, and is used for deploying artifacts +You should set _artifactoryPublish_ as one of the Gradle tasks in the task(s) fields. +_artifactoryPublish_ is a task that is exposed by the Gradle Artifactory Plugin, and is used for deploying artifacts as well as publishing build-info to Artifactory. ![gradle.png](images/gradle-task.png) @@ -513,19 +667,20 @@ as well as publishing build-info to Artifactory.
- + #### JFrog Npm Task + ![npm.png](images/marketplace/npm.png) -The *JFrog Npm* task allows triggering npm builds, while resolving npm dependencies and deploying npm packages from +The _JFrog Npm_ task allows triggering npm builds, while resolving npm dependencies and deploying npm packages from and to Artifactory. -The task uses the configured *JFrog Artifactory V2* service connection. +The task uses the configured _JFrog Artifactory V2_ service connection. The task can be also configured to capture build-info and store the uploaded files as artifacts in it. -The captured build-info can be later published to Artifactory using the *[JFrog Publish Build-Info](#JFrog-Publish-Build-Info)* task. +The captured build-info can be later published to Artifactory using the _[JFrog Publish Build-Info](#jfrog-publish-build-info)_ task. ![npm.png](images/npm-task.png) @@ -548,20 +703,20 @@ see [Artifactory npm Registry](https://jfrog.com/help/r/jfrog-artifactory-docume
- + #### JFrog Nuget and .NET Core Task - + ![nuget.png](images/marketplace/nuget.png) -The *JFrog Nuget* and *JFrog .NET Core* tasks allow restoring NuGet packages from Artifactory. +The _JFrog Nuget_ and _JFrog .NET Core_ tasks allow restoring NuGet packages from Artifactory. These tasks also allow publishing NuGet packages to Artifactory. -The task uses the configured *JFrog Artifactory V2* service connection. +The task uses the configured _JFrog Artifactory V2_ service connection. The tasks can be configured to capture build-info. The build-info stores the restored packages as build dependencies and uploaded packages as build artifacts. -The captured build-info can be later published to Artifactory using the *[JFrog Publish Build-Info](#JFrog-Publish-Build-Info)* task. +The captured build-info can be later published to Artifactory using the _[JFrog Publish Build-Info](#jfrog-publish-build-info)_ task. ![nuget.png](images/nuget-task.png) @@ -580,18 +735,20 @@ The captured build-info can be later published to Artifactory using the *[JFrog For more information about Nuget repositories, see [Artifactory NuGet Repositories](https://jfrog.com/help/r/jfrog-artifactory-documentation/nuget-repositories) +
- + #### JFrog Pip Task + ![pip.png](images/marketplace/pip.png) -The *JFrog Pip* task allows installing Pip packages from Artifactory. -The task uses the configured *JFrog Artifactory V2* service connection. +The _JFrog Pip_ task allows installing Pip packages from Artifactory. +The task uses the configured _JFrog Artifactory V2_ service connection. The tasks can also be configured to capture build-info. The build-info stores the installed packages as build dependencies. The captured build-info can be later published to Artifactory using @@ -610,17 +767,17 @@ the [Publishing Build Info to Artifactory](http://www.jfrog.com#PublishingBuildI buildNumber: '$(Build.BuildNumber)' ``` -*Recording all dependencies as part of the build-info* -When running the *JFrog Pip* task inside a Python environment, which already has some of the packages installed, the +_Recording all dependencies as part of the build-info_ +When running the _JFrog Pip_ task inside a Python environment, which already has some of the packages installed, the installed packages will not be included as part of the build-info, if they were not originally installed from Artifactory. A warning message will be added to the build log in this case. -*How to include all packages in the build-info?* -Running the task for the first time with the *Disable local pip cache* option checked, +_How to include all packages in the build-info?_ +Running the task for the first time with the _Disable local pip cache_ option checked, should re-download and install these packages, and they will therefore be included in the build-info. It is also recommended to run the command from inside a [virtual environment](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/). -The *Virtual environment setup command* field allows this. +The _Virtual environment setup command_ field allows this. ![pip-advanced.png](images/pip-advanced.png) @@ -631,25 +788,26 @@ included in the build-info, even if they are already cached locally.
- + #### JFrog Conan Task + ![conan.png](images/marketplace/conan.png) [Conan](https://conan.io/) is a package manager for C and C++. -The *JFrog Conan* task allows triggering a conan build while resolving conan dependencies from a conan repository in +The _JFrog Conan_ task allows triggering a conan build while resolving conan dependencies from a conan repository in Artifactory. -The task uses the configured *JFrog Artifactory V2* service connection. +The task uses the configured _JFrog Artifactory V2_ service connection. It also allows publishing conan packages to an Artifactory conan repository. The task can be also configured to capture build-info and store the downloaded and uploaded packages as build dependencies and artifact. -The captured build-info can be later published to Artifactory using the *[JFrog Publish Build-Info](#JFrog-Publish-Build-Info)* task. +The captured build-info can be later published to Artifactory using the _[JFrog Publish Build-Info](#jfrog-publish-build-info)_ task. -The task supports the *config install* , *add remote* , *create* and *upload* conan commands. -In addition, it supports a *custom* option, allowing to configure the task to execute any conan command. +The task supports the _config install_ , _add remote_ , _create_ and _upload_ conan commands. +In addition, it supports a _custom_ option, allowing to configure the task to execute any conan command. The full documentation of Conan is available at the [conan website](https://docs.conan.io/en/latest/). ![conan.png](images/conan-task.png) @@ -665,20 +823,22 @@ The full documentation of Conan is available at the [conan website](https://docs For more information about Conan repositories, see [Artifactory Conan Repositories](https://jfrog.com/help/r/jfrog-artifactory-documentation/conan-repositories) +
- + #### JFrog Go Task + -The *JFrog Go* task allows triggering a go build, while resolving go dependencies from a go repository in Artifactory. -The task uses the configured *JFrog Artifactory V2* service connection. +The _JFrog Go_ task allows triggering a go build, while resolving go dependencies from a go repository in Artifactory. +The task uses the configured _JFrog Artifactory V2_ service connection. It also allows publishing go packages to an Artifactory go repository. The task can be also configured to capture build-info and store the downloaded and uploaded packages as build dependencies and artifact. -The captured build-info can be later published to Artifactory using the *JFrog Publish Build-Info* task. +The captured build-info can be later published to Artifactory using the _JFrog Publish Build-Info_ task. ![go.png](images/go-task.png) @@ -697,26 +857,26 @@ The captured build-info can be later published to Artifactory using the *JFrog P For more information about Go repositories, see [Artifactory Go Repositories](https://jfrog.com/help/r/jfrog-artifactory-documentation/go-registry) -
+
## Build Tasks -
- + #### JFrog Collect Build Issues + Being able to look at the build which was published to Artifactory, and see all JIRA issues associated with it, is one of the most powerful capabilities of Artifactory when it comes to managing metadata about artifacts builds. -The *JFrog Collect Build Issues* task collects the list of tracked project issues (for example, issues stored in JIRA, +The _JFrog Collect Build Issues_ task collects the list of tracked project issues (for example, issues stored in JIRA, GitHub or any other bug tracking systems, and adds these issues to the build-info. -The task uses the configured *JFrog Artifactory V2* service connection. The issues are collected by reading the git +The task uses the configured _JFrog Artifactory V2_ service connection. The issues are collected by reading the git commit messages from the local git log. Each commit message is matched against a pre-configured regular expression, which retrieves the issue ID and issue summary. @@ -742,7 +902,7 @@ issues: ##### Configuration properties | Property name | Description | -|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Version | The schema version is intended for internal use. Do not change! | | trackerName | The name (type) of the issue tracking system. For example, JIRA. This property can take any value. | | regexp | A regular expression used for matching the git commit messages. The expression should include two capturing groups - for the issue key (ID) and the issue summary. In the example above, the regular expression matches the commit messages as displayed in the following example:
HAP-1007 - This is a sample issue | @@ -759,14 +919,15 @@ It can then be accesses and used by this task.
- + #### JFrog Publish Build Info + Most of the JFrog tasks can be configured to collect and store build-info locally. -The task uses the configured *JFrog Artifactory V2* service connection. -The collected build info can be then published to Artifactory using the *JFrog Publish Build Info* task. +The task uses the configured _JFrog Artifactory V2_ service connection. +The collected build info can be then published to Artifactory using the _JFrog Publish Build Info_ task. For more information about Build Info, see [Artifactory Build Integration](https://jfrog.com/help/r/jfrog-cli/build-integration) @@ -784,7 +945,7 @@ collect environment variables from the agent and add them to the build-info. excludeEnvVars: '*password*;*psw*;*secret*;*key*;*token*;*auth*;' ``` -After the build-info is published to Artifactory, it can be accessed from the *Artifactory* tab in the Build Results. +After the build-info is published to Artifactory, it can be accessed from the _Artifactory_ tab in the Build Results. ![build-results.png](images/marketplace/build-results.png) ![bi-in-artifactory.png](images/marketplace/bi-in-artifactory.png) @@ -792,36 +953,36 @@ After the build-info is published to Artifactory, it can be accessed from the *A
- + #### JFrog Build Promotion - + To support the artifacts life-cycle, Artifactory supports promoting published builds from one repository to another. -The *JFrog Build Promotion* task promotes a build, by either copying or moving the build artifacts and/or dependencies +The _JFrog Build Promotion_ task promotes a build, by either copying or moving the build artifacts and/or dependencies to a target repository. This task can be added as part of a Build or Release pipeline. -Run these steps to configure the *JFrog Build Promotion* task: +Run these steps to configure the _JFrog Build Promotion_ task: -1. Select the configured *JFrog Artifactory V2* service connection, to which the build has been published. +1. Select the configured _JFrog Artifactory V2_ service connection, to which the build has been published. -2. Specify the name of a* target repository* to which the build should be promoted. +2. Specify the name of a*target repository* to which the build should be promoted. -3. Set the *status* of the build and optionally add a *Comment*. These details will be visible as part of the Build +3. Set the _status_ of the build and optionally add a _Comment_. These details will be visible as part of the Build History in the Artifactory UI. -4. (Optional) Set a *source repository* for the promotion. +4. (Optional) Set a _source repository_ for the promotion. -5. Select the *include build dependencies* if you want the build dependencies to be promoted. +5. Select the _include build dependencies_ if you want the build dependencies to be promoted. -6. To copy and not to move the artifacts to the target repository, select the *Use copy* option to copy the artifacts +6. To copy and not to move the artifacts to the target repository, select the _Use copy_ option to copy the artifacts to the target repository. -7. Select *Dry run* to test the promotion prior to running the build promotion. +7. Select _Dry run_ to test the promotion prior to running the build promotion. ![build-promotion.png](images/marketplace/build-promotion.png) @@ -844,24 +1005,24 @@ Run these steps to configure the *JFrog Build Promotion* task: You can control the life cycle of your artifacts by promoting them from one Artifactory repository to another. Build Promotion can come in handy when embedding it as part of release pipeline in Azure DevOps. -To help you achieve this, follow these steps for creating a release which includes the *JFrog Build Promotion* task. +To help you achieve this, follow these steps for creating a release which includes the _JFrog Build Promotion_ task. 1. Create a new Release. ![promotion.png](images/promotion1.png) -2. Click *environment* and select a template for the release. +2. Click _environment_ and select a template for the release. ![promotion.png](images/promotion2.png) -3. Click *Artifact* and select *Build* as the source type. +3. Click _Artifact_ and select _Build_ as the source type. 4. Fill out the rest of the form details. 5. If you'd like this release to always use the latest build from Artifactory, select specify a specific build number - as the *Default version* and select one of the available build number i the *Build number* list box. + as the _Default version_ and select one of the available build number i the _Build number_ list box. 6. If you'd like to promote a specific build number during the release, select specify at the time of release - creation as the *Default version*: + creation as the _Default version_: ![promotion.png](images/promotion3.png) -7. If you wish to promote the latest build number, select specify a specific build number as the *Default version* - and then select *any* build number. Then, click on the *Variables* tab and add - the *ARTIFACTORY_RELEASE_BUILD_NUMBER* pipeline variable with *LATEST* as the value. +7. If you wish to promote the latest build number, select specify a specific build number as the _Default version_ + and then select _any_ build number. Then, click on the _Variables_ tab and add + the _ARTIFACTORY_RELEASE_BUILD_NUMBER_ pipeline variable with _LATEST_ as the value. ![promotion.png](images/promotion4.png) -8. Configure the *Artifactory Build Promotion* task as one of your release pipeline tasks. +8. Configure the _Artifactory Build Promotion_ task as one of your release pipeline tasks. The task uses a build number which will be selected later on, upon creating a release. ![promotion.png](images/promotion5.png) 9. That's it, you're done! @@ -872,16 +1033,17 @@ To help you achieve this, follow these steps for creating a release which includ
- + #### Discarding Published Builds from Artifactory + -To discard old runs of a build from Artifactory, add the *JFrog Discard Builds* task to the pipeline. +To discard old runs of a build from Artifactory, add the _JFrog Discard Builds_ task to the pipeline. Run these steps to configure the task. -1. Select the configured *JFrog Artifactory V2* service connection, on which you'd like the builds to be discarded. +1. Select the configured _JFrog Artifactory V2_ service connection, on which you'd like the builds to be discarded. 2. Type the name of the build. @@ -915,14 +1077,14 @@ Run these steps to configure the task. ## JFrog Xray tasks
- + #### Audit project's dependencies for Security Vulnerabilities - + -The *JFrog Audit* task triggers an audit of your project dependencies for security vulnerabilities with JFrog Xray. -The task uses the configured *JFrog Xray V2* service connection. +The _JFrog Audit_ task triggers an audit of your project dependencies for security vulnerabilities with JFrog Xray. +The task uses the configured _JFrog Xray V2_ service connection. The scan is synchronous, meaning the tasks waits for the scan to finish. To determine the policy for identifying the vulnerabilities, you can either set a list for Xray Watches or select a JFrog Project or path in Artifactory associated with the policy. @@ -944,17 +1106,18 @@ JFrog Project or path in Artifactory associated with the policy.
- + #### Scanning Published Builds for Security Vulnerabilities + -The *JFrog Build Scan* task allows triggering a build scan with JFrog Xray. -For the build to be scanned, it first needs to be published to Artifactory using the *[JFrog Publish Build-Info](#JFrog-Publish-Build-Info)* task. -The task uses the configured *JFrog Xray V2* service connection. +The _JFrog Build Scan_ task allows triggering a build scan with JFrog Xray. +For the build to be scanned, it first needs to be published to Artifactory using the _[JFrog Publish Build-Info](#jfrog-publish-build-info)_ task. +The task uses the configured _JFrog Xray V2_ service connection. When the scan is triggered, Xray starts scanning the build artifacts and dependencies. The scan is synchronous, meaning the tasks waits for the scan to finish. -If the *Allow fail build* task option is set and Xray is configured to fail the build, the build pipeline will fail, +If the _Allow fail build_ task option is set and Xray is configured to fail the build, the build pipeline will fail, if vulnerabilities are found. > This functionality requires version 3.37.0 or above of JFrog Xray. @@ -979,23 +1142,23 @@ build-info report.
-
## JFrog Docker tasks
- + #### Pushing and Pulling Docker Images to and from Artifactory + -The *JFrog Docker* task allows pushing and pulling docker images to and from a docker repository in Artifactory. +The _JFrog Docker_ task allows pushing and pulling docker images to and from a docker repository in Artifactory. The task can be also configured to capture build-info for the pushed or pulled image. In addition to details about the build and the build environment, the build info includes the image layers as build dependencies and build artifacts. The task stores build info locally on the build agent. -The stored build-info can be later published to Artifactory using the *JFrog Publish Build Info* task. +The stored build-info can be later published to Artifactory using the _JFrog Publish Build Info_ task. > This functionality requires version 7.33.3 or above of Artifactory. @@ -1018,14 +1181,14 @@ see [Artifactory Docker Registry](https://jfrog.com/help/r/jfrog-artifactory-doc
-
- + #### Scanning Local Docker Images with JFrog Xray + -The *JFrog Docker* task allows scanning local docker images using JFrog Xray. The scan results is displayed in the +The _JFrog Docker_ task allows scanning local docker images using JFrog Xray. The scan results is displayed in the build log. By default, the result will include all vulnerabilities found. You may however configure the task to show only @@ -1057,12 +1220,10 @@ You do this by configuring the task to use:
-
## Using Published Artifacts in a Release - Artifacts which were published to Artifactory can be made available for a Release Pipeline. There are two ways to achieve this: @@ -1070,9 +1231,10 @@ There are two ways to achieve this: #### Using JFrog Generic Artifacts task + -The first way is to use the [JFrog Generic Artifacts](#Managing-Generic-Artifacts) task to download the files during the +The first way is to use the [JFrog Generic Artifacts](#managing-generic-artifacts) task to download the files during the release. Read more about this in the Downloading Generic Dependencies from Artifactory section. @@ -1082,6 +1244,7 @@ the Downloading Generic Dependencies from Artifactory section. #### Using Azure Artifact source + You can also set Artifactory as an artifact source for the release. @@ -1091,34 +1254,34 @@ Info to Artifactory section. Follow these steps to add Artifactory as an artifact source to a Release. -1. Create a new Release and click on *Artifacts Add* +1. Create a new Release and click on _Artifacts Add_ - ![release1.png](images/release1.png) + ![release1.png](images/release1.png) -2. Select the *Artifactory* source type. +2. Select the _Artifactory_ source type. - ![release2.png](images/release2.png) + ![release2.png](images/release2.png) 3. Select an Artifactory service, a build name, and the default version to use. - ![release3.png](images/release3.png) + ![release3.png](images/release3.png) - That's it! You're done. + That's it! You're done. - Now, when initiating the Release, the artifacts associated with the defined build are downloaded to the release - agent. + Now, when initiating the Release, the artifacts associated with the defined build are downloaded to the release + agent.
-
## Managing and Distributing Release Bundles
- + #### JFrog Distribution V2 Task + [JFrog Distribution](https://jfrog.com/help/r/jfrog-distribution-documentation) is a centralized platform that lets you @@ -1133,19 +1296,19 @@ As part of the release flow, release bundles are verified by the target destinat correctly and safe to use. JFrog DistributionDistributing Release Bundles -The *JFrog Distribution* task allows creating, updating, signing and deleting release bundles. +The _JFrog Distribution_ task allows creating, updating, signing and deleting release bundles. It also allows distributing the release to the edge nodes. -* The task requires configuring your *JFrog Distribution V2* instance as a service connection in Azure DevOps. -* You can then set the instance you configured as the Distribution service value in the task. -* The task triggers [JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli) to execute the distribution actions. -* When creating or updating a release bundle, you need to - provide [File Specs](https://jfrog.com/help/r/jfrog-integrations-documentation/using-file-specs) defining the - artifacts to be included in the release bundle. -* When distributing a release bundle, you can control the distribution destinations by defining rules distribution rules - in a JSON format. +- The task requires configuring your _JFrog Distribution V2_ instance as a service connection in Azure DevOps. +- You can then set the instance you configured as the Distribution service value in the task. +- The task triggers [JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli) to execute the distribution actions. +- When creating or updating a release bundle, you need to + provide [File Specs](https://jfrog.com/help/r/jfrog-integrations-documentation/using-file-specs) defining the + artifacts to be included in the release bundle. +- When distributing a release bundle, you can control the distribution destinations by defining rules distribution rules + in a JSON format. -*Distribution Rules JSON structure* Here's an example: +_Distribution Rules JSON structure_ Here's an example: ```JSON { @@ -1200,12 +1363,10 @@ The Distribution Rules format also supports wildcards. For example:
-
## Contribution - We welcome pull requests from the community!
@@ -1217,6 +1378,7 @@ To build and run the extension sources, please follow these steps: 1. Clone the code from git. 2. To Build and create the JFrog Artifactory extension `vsix` file, run the following command. + ``` npm i npm run create @@ -1238,6 +1400,7 @@ Use the following commands to run from terminal: 1. Set the ADO_JFROG_PLATFORM_URL, ADO_JFROG_PLATFORM_USERNAME and ADO_JFROG_PLATFORM_PASSWORD environment variables with your JFrog Platform URL, username and password: + ``` export ADO_JFROG_PLATFORM_URL='https://myrepo.jfrog.io/' export ADO_JFROG_PLATFORM_USERNAME=admin @@ -1245,6 +1408,7 @@ Use the following commands to run from terminal: ``` 2. Run the following commands: + ``` npm i -g jfrog-cli-v2-jf npm t @@ -1255,10 +1419,10 @@ ts-node: `mocha -r ts-node/register tests.ts -t 1000000`. #### Skipping Tests -In order to skip tests, set the ADO_SKIP_TESTS environment variable with the tests you wish to skip, separated by +In order to skip tests, set the ADO*SKIP_TESTS environment variable with the tests you wish to skip, separated by commas. -The supported values are: *maven*, *gradle*, *npm*, *go*, *nuget*, *dotnet*, *conan*, *pip*, *proxy*, -*distribution*, *unit*, *installer* and *generic*. +The supported values are: \_maven*, _gradle_, _npm_, _go_, _nuget_, _dotnet_, _conan_, _pip_, _proxy_, +_distribution_, _unit_, _installer_ and _generic_. For example, for skipping the nuget and dotnet tests: @@ -1271,14 +1435,13 @@ export ADO_SKIP_TESTS=nuget,dotnet
Pull request guidelines -* Pull requests should be created on the *dev* branch. -* Please make sure the code is covered by tests. -* Please run `npm run format` for formatting the code before submitting the pull request. -* Please run `npm run lint` and make sure no new tslint warnings were introduced. +- Pull requests should be created on the _dev_ branch. +- Please make sure the code is covered by tests. +- Please run `npm run format` for formatting the code before submitting the pull request. +- Please run `npm run lint` and make sure no new tslint warnings were introduced.
## Reporting issues Please help us improve jfrog-azure-devops-extension by [reporting issues](https://github.com/jfrog/jfrog-azure-devops-extension/issues/new/choose) you encounter. - diff --git a/images/oidc-integration.png b/images/oidc-integration.png new file mode 100644 index 0000000000000000000000000000000000000000..183ebe15eb26a08f57b8c2aab0bede8167ef2042 GIT binary patch literal 52369 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%0D>iEp0(}z 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 literal 0 HcmV?d00001 diff --git a/images/oidc-service-connection.png b/images/oidc-service-connection.png new file mode 100644 index 0000000000000000000000000000000000000000..ff7c66ab77cb0e439fb4556709af31ff38e0376d GIT binary patch literal 106061 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 a}~-7>t>F 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 H)${#-jFqE@ literal 0 HcmV?d00001 diff --git a/jfrog-tasks-utils/package.json b/jfrog-tasks-utils/package.json index 441564f6..8719b646 100644 --- a/jfrog-tasks-utils/package.json +++ b/jfrog-tasks-utils/package.json @@ -11,7 +11,8 @@ "azure-pipelines-task-lib": "4.5.0", "azure-pipelines-tool-lib": "2.0.6", "azure-pipelines-tasks-java-common": "^2.219.1", - "typed-rest-client": "^1.8.11" + "typed-rest-client": "^1.8.11", + "sync-request": "^6.1.0" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" diff --git a/jfrog-tasks-utils/utils.js b/jfrog-tasks-utils/utils.js index 8f34c6e6..7aebddb2 100644 --- a/jfrog-tasks-utils/utils.js +++ b/jfrog-tasks-utils/utils.js @@ -19,7 +19,7 @@ const buildAgent = 'jfrog-azure-devops-extension'; const customFolderPath = encodePath(join(jfrogFolderPath, 'current')); const customCliPath = encodePath(join(customFolderPath, fileName)); // Optional - Customized jfrog-cli path. const jfrogCliReleasesUrl = 'https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf'; - +const request = require('sync-request'); // Set by Tools Installer Task. This JFrog CLI version will be used in all tasks unless manual installation is used, // or a specific version was requested in a task. If not set, use the default CLI version. const pipelineRequestedCliVersionEnv = 'JFROG_CLI_PIPELINE_REQUESTED_VERSION_AZURE'; @@ -252,15 +252,90 @@ function configureDistributionCliServer(distributionService, serverId, cliPath, function configureXrayCliServer(xrayService, serverId, cliPath, buildDir) { return configureSpecificCliServer(xrayService, '--xray-url', serverId, cliPath, buildDir); } +function logIDToken(oidcToken) { + const oidcClaims = JSON.parse(Buffer.from(oidcToken.split('.')[1], 'base64').toString()); + console.log('OIDC Token Subject: ', oidcClaims.sub); + console.log(`OIDC Token Claims: {"sub": "${oidcClaims.sub}"}`); + console.log('OIDC Token Issuer (Provider URL): ', oidcClaims.iss); + console.log('OIDC Token Audience: ', oidcClaims.aud); +} + +function getADOIdToken(serviceConnectionID) { + const uri = tl.getVariable('System.CollectionUri'); + const teamPrjID = tl.getVariable('System.TeamProjectId'); + const hub = tl.getVariable('System.HostType'); + const planID = tl.getVariable('System.PlanId'); + const jobID = tl.getVariable('System.JobId'); + const apiVersion = '7.1-preview.1'; + + const url = `${uri}${teamPrjID}/_apis/distributedtask/hubs/${hub}/plans/${planID}/jobs/${jobID}/oidctoken?api-version=${apiVersion}&serviceConnectionId=${serviceConnectionID}`; + + try { + const response = request('POST', url, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${tl.getVariable('System.AccessToken')}`, + }, + }); + + if (response.statusCode !== 200) { + throw new Error(`HTTP request failed with status code ${response.statusCode}`); + } + + const parsedResponse = JSON.parse(response.getBody('utf8')); + const idToken = parsedResponse.oidcToken; + logIDToken(idToken); + return idToken; + } catch (error) { + throw new Error(`Failed to get or parse response: ${error.message}`); + } +} + +function getArtifactoryAccessToken(adoJWT, oidcProviderName, jfrogPlatformUrl) { + const payload = { + grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange', + subject_token_type: 'urn:ietf:params:oauth:token-type:id_token', + subject_token: adoJWT, + provider_name: oidcProviderName, + }; + + const url = `${jfrogPlatformUrl}/access/api/v1/oidc/token`; + + try { + const response = request('POST', url, { + headers: { + 'Content-Type': 'application/json', + }, + json: payload, + }); + + if (response.statusCode !== 200) { + throw new Error(`HTTP request failed with status code ${response.statusCode}: ${response.getBody('utf8')}`); + } + + const parsedResponse = JSON.parse(response.getBody('utf8')); + return parsedResponse.access_token; + } catch (error) { + throw new Error(`Failed to get or parse response: ${error.message}`); + } +} function configureSpecificCliServer(service, urlFlag, serverId, cliPath, buildDir) { let serviceUrl = tl.getEndpointUrl(service, false); let serviceUser = tl.getEndpointAuthorizationParameter(service, 'username', true); let servicePassword = tl.getEndpointAuthorizationParameter(service, 'password', true); let serviceAccessToken = tl.getEndpointAuthorizationParameter(service, 'apitoken', true); + let oidcProviderName = tl.getEndpointAuthorizationParameter(service, 'oidcProviderName', true); + let jfrogPlatformUrl = tl.getEndpointAuthorizationParameter(service, 'jfrogPlatformUrl', true); let cliCommand = cliJoin(cliPath, jfrogCliConfigAddCommand, quote(serverId), urlFlag + '=' + quote(serviceUrl), '--interactive=false'); let stdinSecret; let secretInStdinSupported = isStdinSecretSupported(); + + if (oidcProviderName) { + const idToken = getADOIdToken(service); + serviceAccessToken = getArtifactoryAccessToken(idToken, oidcProviderName, jfrogPlatformUrl); + } + if (serviceAccessToken) { // Add access-token if required. cliCommand = cliJoin(cliCommand, secretInStdinSupported ? '--access-token-stdin' : '--access-token=' + quote(serviceAccessToken)); diff --git a/vss-extension.json b/vss-extension.json index 2f572a34..27ae9929 100644 --- a/vss-extension.json +++ b/vss-extension.json @@ -149,6 +149,37 @@ } } ] + }, + { + "type": "ms.vss-endpoint.endpoint-auth-scheme-none", + "displayName": "OpenID Connect Integration", + "properties": { + "isVerifiable": "False" + }, + "inputDescriptors": [ + { + "id": "oidcProviderName", + "name": "OpenID Connect Provider Name", + "description": "The OpenID Connect \"Provider Name\" configured in JFrog Platform. Click here for information about how to configure OpenID Connect.", + "inputMode": "textbox", + "isConfidential": false, + "validation": { + "isRequired": true, + "dataType": "string" + } + }, + { + "id": "jfrogPlatformUrl", + "name": "Platform URL", + "description": "The access token will be obtained from this URL. For example, https://my.jfrog.io/", + "inputMode": "textbox", + "isConfidential": false, + "validation": { + "isRequired": true, + "dataType": "string" + } + } + ] } ] } @@ -165,7 +196,7 @@ "displayName": "JFrog Artifactory V2", "url": { "displayName": "Server URL", - "helpText": "Specify the root URL of your Artifactory installation. For example, https://repo.jfrog.org/artifactory" + "helpText": "Specify the root URL of your Artifactory installation. For example, https://my.jfrog.io/artifactory" }, "icon": "images/artifactory.png", "dataSources": [ @@ -234,6 +265,37 @@ } } ] + }, + { + "type": "ms.vss-endpoint.endpoint-auth-scheme-none", + "displayName": "OpenID Connect Integration", + "properties": { + "isVerifiable": "False" + }, + "inputDescriptors": [ + { + "id": "oidcProviderName", + "name": "OpenID Connect Provider Name", + "description": "The OpenID Connect \"Provider Name\" configured in JFrog Platform. Click here for information about how to configure OpenID Connect.", + "inputMode": "textbox", + "isConfidential": false, + "validation": { + "isRequired": true, + "dataType": "string" + } + }, + { + "id": "jfrogPlatformUrl", + "name": "Platform URL", + "description": "The access token will be obtained from this URL. For example, https://my.jfrog.io/", + "inputMode": "textbox", + "isConfidential": false, + "validation": { + "isRequired": true, + "dataType": "string" + } + } + ] } ] } @@ -250,7 +312,7 @@ "displayName": "JFrog Distribution V2", "url": { "displayName": "Server URL", - "helpText": "Specify the root URL of your Distribution installation. For example, https://repo.jfrog.org/distribution" + "helpText": "Specify the root URL of your Distribution installation. For example, https://my.jfrog.io/distribution" }, "icon": "images/distribution.png", "dataSources": [ @@ -309,6 +371,37 @@ } } ] + }, + { + "type": "ms.vss-endpoint.endpoint-auth-scheme-none", + "displayName": "OpenID Connect Integration", + "properties": { + "isVerifiable": "False" + }, + "inputDescriptors": [ + { + "id": "oidcProviderName", + "name": "OpenID Connect Provider Name", + "description": "The OpenID Connect \"Provider Name\" configured in JFrog Platform. Click here for information about how to configure OpenID Connect.", + "inputMode": "textbox", + "isConfidential": false, + "validation": { + "isRequired": true, + "dataType": "string" + } + }, + { + "id": "jfrogPlatformUrl", + "name": "Platform URL", + "description": "The access token will be obtained from this URL. For example, https://my.jfrog.io/", + "inputMode": "textbox", + "isConfidential": false, + "validation": { + "isRequired": true, + "dataType": "string" + } + } + ] } ] } @@ -325,7 +418,7 @@ "displayName": "JFrog Xray V2", "url": { "displayName": "Server URL", - "helpText": "Specify the root URL of your Xray installation. For example, https://repo.jfrog.org/xray" + "helpText": "Specify the root URL of your Xray installation. For example, https://my.jfrog.io/xray" }, "icon": "images/xray.png", "dataSources": [ @@ -384,6 +477,37 @@ } } ] + }, + { + "type": "ms.vss-endpoint.endpoint-auth-scheme-none", + "displayName": "OpenID Connect Integration", + "properties": { + "isVerifiable": "False" + }, + "inputDescriptors": [ + { + "id": "oidcProviderName", + "name": "OpenID Connect Provider Name", + "description": "The OpenID Connect \"Provider Name\" configured in JFrog Platform. Click here for information about how to configure OpenID Connect.", + "inputMode": "textbox", + "isConfidential": false, + "validation": { + "isRequired": true, + "dataType": "string" + } + }, + { + "id": "jfrogPlatformUrl", + "name": "Platform URL", + "description": "The access token will be obtained from this URL. For example, https://my.jfrog.io/", + "inputMode": "textbox", + "isConfidential": false, + "validation": { + "isRequired": true, + "dataType": "string" + } + } + ] } ] } @@ -908,4 +1032,4 @@ "path": "tasks/JFrogGenericArtifacts" } ] -} \ No newline at end of file +} From 9c9eeedb984894943e3e93834899dde10541cacc Mon Sep 17 00:00:00 2001 From: Henrik Stanley Mortensen <31671391+HenrikStanley@users.noreply.github.com> Date: Wed, 6 Nov 2024 16:25:36 +0100 Subject: [PATCH 02/26] fix: URLs to match the new jfrog.io url default --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 58fe04e5..021a842d 100644 --- a/README.md +++ b/README.md @@ -404,9 +404,9 @@ This requires you to fill in the following inputs: | Property name | Description | | ---------------------------- | ------------------------------------------------------------------------------------------------------ | -| Server URL | The URL of your JFrog instance with the `/artifactory` path fx. (`https://repo.jfrog.org/artifactory`) | +| Server URL | The URL of your JFrog instance with the `/artifactory` path fx. (`https://my.jfrog.io/artifactory`) | | OpenID Connect Provider Name | The `Provider Name` you configured in the `Configure OpenID Connect Integration` step | -| Platform URL | The URL of your JFrog instance fx. (`https://repo.jfrog.org/`) | +| Platform URL | The URL of your JFrog instance fx. (`https://my.jfrog.io/`) | | Service connection name | The name of the Service Connection, must match the values put into the `JSON Claims mapping` | | Description (optional) | A short of the purpose of this ServiceConnection | From fa496051db8e5dd3198fb4b1f2f8f68778761e56 Mon Sep 17 00:00:00 2001 From: David Winslow Date: Thu, 7 Nov 2024 11:12:20 +0100 Subject: [PATCH 03/26] fix: renaming variable to idToken --- jfrog-tasks-utils/utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jfrog-tasks-utils/utils.js b/jfrog-tasks-utils/utils.js index 7aebddb2..e3b11836 100644 --- a/jfrog-tasks-utils/utils.js +++ b/jfrog-tasks-utils/utils.js @@ -291,11 +291,11 @@ function getADOIdToken(serviceConnectionID) { } } -function getArtifactoryAccessToken(adoJWT, oidcProviderName, jfrogPlatformUrl) { +function getArtifactoryAccessToken(idToken, oidcProviderName, jfrogPlatformUrl) { const payload = { grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange', subject_token_type: 'urn:ietf:params:oauth:token-type:id_token', - subject_token: adoJWT, + subject_token: idToken, provider_name: oidcProviderName, }; From a16196dc8a1ed5f92ff7be30e8b14b264ac2b395 Mon Sep 17 00:00:00 2001 From: delarea Date: Sun, 6 Apr 2025 14:36:42 +0300 Subject: [PATCH 04/26] Update to use the latest supported OIDC cli --- jfrog-tasks-utils/utils.js | 39 +++++++------------------------------- vss-extension.json | 11 ----------- 2 files changed, 7 insertions(+), 43 deletions(-) diff --git a/jfrog-tasks-utils/utils.js b/jfrog-tasks-utils/utils.js index b5640c12..b622ec62 100644 --- a/jfrog-tasks-utils/utils.js +++ b/jfrog-tasks-utils/utils.js @@ -10,7 +10,7 @@ const fileName = getCliExecutableName(); const jfrogCliToolName = 'jf'; const cliPackage = 'jfrog-cli-' + getArchitecture(); const jfrogFolderPath = encodePath(join(tl.getVariable('Agent.ToolsDirectory') || '', '_jf')); -const defaultJfrogCliVersion = '2.71.3'; +const defaultJfrogCliVersion = '2.75.0'; const minCustomCliVersion = '2.10.0'; const minSupportedStdinSecretCliVersion = '2.36.0'; const minSupportedServerIdEnvCliVersion = '2.37.0'; @@ -291,49 +291,24 @@ function getADOIdToken(serviceConnectionID) { } } -function getArtifactoryAccessToken(idToken, oidcProviderName, jfrogPlatformUrl) { - const payload = { - grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange', - subject_token_type: 'urn:ietf:params:oauth:token-type:id_token', - subject_token: idToken, - provider_name: oidcProviderName, - }; - - const url = `${jfrogPlatformUrl}/access/api/v1/oidc/token`; - - try { - const response = request('POST', url, { - headers: { - 'Content-Type': 'application/json', - }, - json: payload, - }); - - if (response.statusCode !== 200) { - throw new Error(`HTTP request failed with status code ${response.statusCode}: ${response.getBody('utf8')}`); - } - - const parsedResponse = JSON.parse(response.getBody('utf8')); - return parsedResponse.access_token; - } catch (error) { - throw new Error(`Failed to get or parse response: ${error.message}`); - } -} - function configureSpecificCliServer(service, urlFlag, serverId, cliPath, buildDir) { let serviceUrl = tl.getEndpointUrl(service, false); let serviceUser = tl.getEndpointAuthorizationParameter(service, 'username', true); let servicePassword = tl.getEndpointAuthorizationParameter(service, 'password', true); let serviceAccessToken = tl.getEndpointAuthorizationParameter(service, 'apitoken', true); let oidcProviderName = tl.getEndpointAuthorizationParameter(service, 'oidcProviderName', true); - let jfrogPlatformUrl = tl.getEndpointAuthorizationParameter(service, 'jfrogPlatformUrl', true); let cliCommand = cliJoin(cliPath, jfrogCliConfigAddCommand, quote(serverId), urlFlag + '=' + quote(serviceUrl), '--interactive=false'); let stdinSecret; let secretInStdinSupported = isStdinSecretSupported(); if (oidcProviderName) { const idToken = getADOIdToken(service); - serviceAccessToken = getArtifactoryAccessToken(idToken, oidcProviderName, jfrogPlatformUrl); + cliCommand = cliJoin( + cliCommand, + '--oidc-provider-name=' + (isWindows() ? quote(oidcProviderName) : singleQuote(oidcProviderName)), + '--oidc-provider-type=' + 'Azure'), + '--oidc-token-id=' + (isWindows() ? quote(idToken) : singleQuote(idToken) + ); } if (serviceAccessToken) { diff --git a/vss-extension.json b/vss-extension.json index c591fc3c..24fe0e05 100644 --- a/vss-extension.json +++ b/vss-extension.json @@ -167,17 +167,6 @@ "isRequired": true, "dataType": "string" } - }, - { - "id": "jfrogPlatformUrl", - "name": "Platform URL", - "description": "The access token will be obtained from this URL. For example, https://my.jfrog.io/", - "inputMode": "textbox", - "isConfidential": false, - "validation": { - "isRequired": true, - "dataType": "string" - } } ] } From 2b41a44cbaf70667a18a54e51f4f6cde753641d5 Mon Sep 17 00:00:00 2001 From: delarea Date: Sun, 6 Apr 2025 18:04:38 +0300 Subject: [PATCH 05/26] execute config add --- jfrog-tasks-utils/utils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jfrog-tasks-utils/utils.js b/jfrog-tasks-utils/utils.js index b622ec62..28fb9740 100644 --- a/jfrog-tasks-utils/utils.js +++ b/jfrog-tasks-utils/utils.js @@ -10,7 +10,7 @@ const fileName = getCliExecutableName(); const jfrogCliToolName = 'jf'; const cliPackage = 'jfrog-cli-' + getArchitecture(); const jfrogFolderPath = encodePath(join(tl.getVariable('Agent.ToolsDirectory') || '', '_jf')); -const defaultJfrogCliVersion = '2.75.0'; +const defaultJfrogCliVersion = '2.74.1'; const minCustomCliVersion = '2.10.0'; const minSupportedStdinSecretCliVersion = '2.36.0'; const minSupportedServerIdEnvCliVersion = '2.37.0'; @@ -309,6 +309,7 @@ function configureSpecificCliServer(service, urlFlag, serverId, cliPath, buildDi '--oidc-provider-type=' + 'Azure'), '--oidc-token-id=' + (isWindows() ? quote(idToken) : singleQuote(idToken) ); + return executeCliCommand(cliCommand, buildDir, { stdinSecret }); } if (serviceAccessToken) { From dfa51581360a53fcbdf7f07994e4f438415e8132 Mon Sep 17 00:00:00 2001 From: delarea Date: Mon, 14 Apr 2025 15:37:37 +0300 Subject: [PATCH 06/26] fix diff --- buildScripts/publish-private.sh | 2 +- jfrog-tasks-utils/utils.js | 13 ++----------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/buildScripts/publish-private.sh b/buildScripts/publish-private.sh index 43f71f93..0c1798a3 100644 --- a/buildScripts/publish-private.sh +++ b/buildScripts/publish-private.sh @@ -30,7 +30,7 @@ npx tfx extension unpublish -t "$ADO_ARTIFACTORY_API_KEY" --extension-id jfrog-a npx tfx extension create --manifest-globs vss-extension-private.json --publisher "$PUBLISHER" # Check that vsix size is less then 30MB vsixSize="$(du -m -- *.vsix | awk '{print $1}' | head -1)" -if [ "${vsixSize}" -gt 40 ]; then +if [ "${vsixSize}" -gt 30 ]; then echo "Extension vsix size is greater than 30MB! (${vsixSize}MB) - Hint: Most of the dependencies on package-json are in format of - <^x.y.z>, so maybe one of them got updated, and the node_modules directory became bigger" exit 1 fi diff --git a/jfrog-tasks-utils/utils.js b/jfrog-tasks-utils/utils.js index a20d1e8b..fee3fbad 100644 --- a/jfrog-tasks-utils/utils.js +++ b/jfrog-tasks-utils/utils.js @@ -10,7 +10,7 @@ const fileName = getCliExecutableName(); const jfrogCliToolName = 'jf'; const cliPackage = 'jfrog-cli-' + getArchitecture(); const jfrogFolderPath = encodePath(join(tl.getVariable('Agent.ToolsDirectory') || '', '_jf')); -const defaultJfrogCliVersion = '2.71.3'; +const defaultJfrogCliVersion = '2.75.0'; const minCustomCliVersion = '2.10.0'; const minSupportedStdinSecretCliVersion = '2.36.0'; const minSupportedServerIdEnvCliVersion = '2.37.0'; @@ -252,13 +252,6 @@ function configureDistributionCliServer(distributionService, serverId, cliPath, function configureXrayCliServer(xrayService, serverId, cliPath, buildDir) { return configureSpecificCliServer(xrayService, '--xray-url', serverId, cliPath, buildDir); } -function logIDToken(oidcToken) { - const oidcClaims = JSON.parse(Buffer.from(oidcToken.split('.')[1], 'base64').toString()); - console.log('OIDC Token Subject: ', oidcClaims.sub); - console.log(`OIDC Token Claims: {"sub": "${oidcClaims.sub}"}`); - console.log('OIDC Token Issuer (Provider URL): ', oidcClaims.iss); - console.log('OIDC Token Audience: ', oidcClaims.aud); -} function getADOIdToken(serviceConnectionID) { const uri = tl.getVariable('System.CollectionUri'); @@ -283,9 +276,7 @@ function getADOIdToken(serviceConnectionID) { } const parsedResponse = JSON.parse(response.getBody('utf8')); - const idToken = parsedResponse.oidcToken; - logIDToken(idToken); - return idToken; + return parsedResponse.oidcToken; } catch (error) { throw new Error(`Failed to get or parse response: ${error.message}`); } From 2ee06ee749460188601609b139a77a80a0927e3d Mon Sep 17 00:00:00 2001 From: delarea Date: Mon, 14 Apr 2025 15:39:14 +0300 Subject: [PATCH 07/26] fix diff --- README.md | 617 ++++++++++++++++++++---------------------------------- 1 file changed, 227 insertions(+), 390 deletions(-) diff --git a/README.md b/README.md index 9b0e565e..be9bb02e 100644 --- a/README.md +++ b/README.md @@ -13,147 +13,120 @@ # Overview -[JFrog](https://jfrog.com/) provides tight integration with [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) through the _[JFrog Extension](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension)_ +[JFrog](https://jfrog.com/) provides tight integration with [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) through the *[JFrog Extension](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension)* Beyond managing efficient deployment of your artifacts to [JFrog Artifactory](https://jfrog.com/artifactory), the extension lets you capture information about artifacts deployed, dependencies resolved, environment data associated with the build runs and more, that effectively facilitates fully traceable builds. -JFrog brings continuous integration to [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) through the _JFrog_ extension. +JFrog brings continuous integration to [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) through the *JFrog* extension. -The _[JFrog Extension](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension)_ for Azure DevOps supports: +The *[JFrog Extension](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension)* for Azure DevOps supports: + +* Running your builds while using [JFrog Artifactory](https://jfrog.com/artifactory) as the binary repository manager. +* Gaining full traceability of your builds by capturing your build-info from your builds and publishing it to [JFrog Artifactory](https://jfrog.com/artifactory). +* Managing your binaries lifecycle with [JFrog Artifactory](https://jfrog.com/artifactory). +* Auditing your projects and scanning your builds with [JFrog Xray](https://jfrog.com/xray). +* Distributing your artifacts with [JFrog Distribution](https://jfrog.com/distribution/). -- Running your builds while using [JFrog Artifactory](https://jfrog.com/artifactory) as the binary repository manager. -- Gaining full traceability of your builds by capturing your build-info from your builds and publishing it to [JFrog Artifactory](https://jfrog.com/artifactory). -- Managing your binaries lifecycle with [JFrog Artifactory](https://jfrog.com/artifactory). -- Auditing your projects and scanning your builds with [JFrog Xray](https://jfrog.com/xray). -- Distributing your artifacts with [JFrog Distribution](https://jfrog.com/distribution/). ## Table of contents -- [JFrog Azure DevOps Extension](#jfrog-azure-devops-extension) -- [Overview](#overview) - - [Table of contents](#table-of-contents) - - [Download and Installation](#download-and-installation) - - [Installing the Extension](#installing-the-extension) - - [Installing the Build Agent](#installing-the-build-agent) - - [Automatic Installation](#automatic-installation) - - [Custom tools Installation](#custom-tools-installation) - - [Manual Installation](#manual-installation) - - [Installing JFrog CLI](#installing-jfrog-cli) - - [Installing the Maven Extractor](#installing-the-maven-extractor) - - [Installing the Gradle Extractor](#installing-the-gradle-extractor) - - [Installing Conan](#installing-conan) - - [Using TFS 2015](#using-tfs-2015) - - [Configuring the Service Connections](#configuring-the-service-connections) - - [Using OpenID Connect (OIDC) Authentication](#using-openid-connect-oidc-authentication) - - [Configure OpenID Connect Integration](#configure-openid-connect-integration) - - [Configure Identity Mappings](#configure-identity-mappings) - - [Configure the Service Connection](#configure-the-service-connection) - - [Executing JFrog CLI Commands](#executing-jfrog-cli-commands) - - [JFrog CLI V2 Task](#jfrog-cli-v2-task) - - [Managing Generic Artifacts](#managing-generic-artifacts) - - [Generic artifacts handling](#generic-artifacts-handling) - - [Downloading generic build dependencies from Artifactory](#downloading-generic-build-dependencies-from-artifactory) - - [Uploading generic build artifacts to Artifactory](#uploading-generic-build-artifacts-to-artifactory) - - [Setting / Deleting properties on files in Artifactory](#setting--deleting-properties-on-files-in-artifactory) - - [Moving / Copying / Deleting artifacts in Artifactory](#moving--copying--deleting-artifacts-in-artifactory) - - [Build tools Tasks](#build-tools-tasks) - - [JFrog Maven Task](#jfrog-maven-task) - - [JFrog Gradle Task](#jfrog-gradle-task) - - [JFrog Npm Task](#jfrog-npm-task) - - [JFrog Nuget and .NET Core Task](#jfrog-nuget-and-net-core-task) - - [JFrog Pip Task](#jfrog-pip-task) - - [JFrog Conan Task](#jfrog-conan-task) - - [JFrog Go Task](#jfrog-go-task) - - [Build Tasks](#build-tasks) - - [JFrog Collect Build Issues](#jfrog-collect-build-issues) - - [Configuration properties](#configuration-properties) - - [JFrog Publish Build Info](#jfrog-publish-build-info) - - [JFrog Build Promotion](#jfrog-build-promotion) - - [Using Build Promotion in a Release](#using-build-promotion-in-a-release) - - [Discarding Published Builds from Artifactory](#discarding-published-builds-from-artifactory) - - [JFrog Xray tasks](#jfrog-xray-tasks) - - [Audit project's dependencies for Security Vulnerabilities](#audit-projects-dependencies-for-security-vulnerabilities) - - [Scanning Published Builds for Security Vulnerabilities](#scanning-published-builds-for-security-vulnerabilities) - - [JFrog Docker tasks](#jfrog-docker-tasks) - - [Pushing and Pulling Docker Images to and from Artifactory](#pushing-and-pulling-docker-images-to-and-from-artifactory) - - [Scanning Local Docker Images with JFrog Xray](#scanning-local-docker-images-with-jfrog-xray) - - [Using Published Artifacts in a Release](#using-published-artifacts-in-a-release) - - [Using JFrog Generic Artifacts task](#using-jfrog-generic-artifacts-task) - - [Using Azure Artifact source](#using-azure-artifact-source) - - [Managing and Distributing Release Bundles](#managing-and-distributing-release-bundles) - - [JFrog Distribution V2 Task](#jfrog-distribution-v2-task) - - [Contribution](#contribution) - - [Building](#building) - - [Testing](#testing) - - [Skipping Tests](#skipping-tests) - - [Reporting issues](#reporting-issues) +- [Table of contents](#Table-of-contents) + - [Overview](#Overview) + - [Download and Installation](#Download-and-Installation) + - [Installing the Extension](#Installing-the-Extension) + - [Installing the Build Agent](#Installing-the-Build-Agent) + - [Configuring the Service Connections](#Configuring-the-Service-Connections) + - [Executing JFrog CLI Commands](#Executing-JFrog-CLI-Commands) + - [Build tools Tasks](#build-tools-tasks) + - [JFrog Maven](#JFrog-Maven-Task) + - [JFrog Gradle](#JFrog-Gradle-Task) + - [JFrog Npm](#JFrog-Npm-Task) + - [JFrog Nuget](#JFrog-Nuget-and-NET-Core-Task) + - [JFrog .NET Core](#JFrog-Nuget-and-NET-Core-Task) + - [JFrog Pip](#JFrog-Pip-Task) + - [JFrog Conan](#JFrog-Conan-Task) + - [JFrog Go](#JFrog-Go-Task) + - [Build Tasks](#Build-tasks) + - [JFrog Collect Build Issues](#JFrog-Collect-Build-Issues) + - [JFrog Publish Build Info](#JFrog-Publish-Build-Info) + - [JFrog Build Promotion](#JFrog-Build-Promotion) + - [Discarding Published Builds](#Discarding-Published-Builds-from-Artifactory) + - [Managing Generic Artifacts](#Managing-Generic-Artifacts) + - [JFrog Xray](#JFrog-Xray-tasks) + - [Audit project's dependencies for Security Vulnerabilities](#Audit-projects-dependencies-for-Security-Vulnerabilities) + - [Scanning Published Builds for Security Vulnerabilities with JFrog Xray](#Scanning-Published-Builds-for-Security-Vulnerabilities) + - [JFrog Docker Tasks](#JFrog-Docker-tasks) + - [Pushing and Pulling Docker Images to and from Artifactory](#Pushing-and-Pulling-Docker-Images-to-and-from-Artifactory) + - [Scanning Local Docker Images with JFrog Xray](#Scanning-Local-Docker-Images-with-JFrog-Xray) + - [JFrog Distribution](#Managing-and-Distributing-Release-Bundles) + - [JFrog Distribution Task](#JFrog-Distribution-V2-Task) + - [Contributions](#Contribution) ## Download and Installation ### Installing the Extension -To install the _[JFrog Extension](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension)_, execute the following steps: +To install the *[JFrog Extension](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension)*, execute the following steps: -- Go to - the [Visual Studio Marketplace Jfrog Extension Page](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension) - and sign in to your account. +* Go to + the [Visual Studio Marketplace Jfrog Extension Page](https://marketplace.visualstudio.com/items?itemName=JFrog.jfrog-azure-devops-extension) + and sign in to your account. - + + +* Click on *Get It Free* -- Click on _Get It Free_ + + +* Select the account to which you want to apply the extension and confirm installation. - +* In the JFrog Extension page, click *Install*. -- Select the account to which you want to apply the extension and confirm installation. + -- In the JFrog Extension page, click _Install_. - ### Installing the Build Agent To run the JFrog tasks, the build agents use the following tools: -- JFrog CLI: Runs all the JFrog tasks. -- Maven Extractor (Used by the [JFrog Maven](#jfrog-maven-task) task) -- Gradle Extractor (Used by the [JFrog Gradle](#jfrog-gradle-task) task) -- Conan client (Used by the [JFrog Conan](#jfrog-conan-task) task) +* JFrog CLI: Runs all the JFrog tasks. +* Maven Extractor (Used by the [JFrog Maven](#jfrog-maven-task) task) +* Gradle Extractor (Used by the [JFrog Gradle](#jfrog-gradle-Task) task) +* Conan client (Used by the [JFrog Conan](#jfrog-conan-task) task)
#### Automatic Installation - If the build agent has access to the internet, JFrog CLI along with the Maven and Gradle Extractors are downloaded and installed automatically on the agent, the first time they are required. -
#### Custom tools Installation - You can configure the pipeline to download JFrog CLI and the Maven Extractor from a JFrog Artifactory instance, which is configured to proxy the download repositories. -- Create two remote repositories in Artifactory: -- Create a remote repository in Artifactory for downloading _JFrog CLI_. Name the repository _jfrog-cli-remote_ and - set its URL - to [https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf/](https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf/) -- Create a remote repository in Artifactory for downloading the _Maven and Gradle Extractors_. Name the URL _extractors_ and set its URL - to: [https://releases.jfrog.io/artifactory/oss-release-local/](https://releases.jfrog.io/artifactory/oss-release-local/) -- Make sure to configure the Artifactory server with the _jfrog-cli-remote_ and _extractors_ repositories in as a - [service connection](#configuring-the-service-connections) in Azure DevOps of type _JFrog Artifactory V2_. -- Add the _JFrog Tools Installer_ task to your build or release pipeline. -- Select the Artifactory service you configured. -- Select _jfrog-cli-remote_ as the target repository to download the JFrog CLI. -- If your pipeline uses the [JFrog Maven](#jfrog-maven-task) or [JFrog Gradle](#jfrog-gradle-task) tasks, select _extractors_ as the repository to - download the Maven Extractor. +* Create two remote repositories in Artifactory: +* Create a remote repository in Artifactory for downloading *JFrog CLI*. Name the repository *jfrog-cli-remote* and + set its URL + to [https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf/](https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf/) +* Create a remote repository in Artifactory for downloading the *Maven and Gradle Extractors*. Name the URL *extractors* and set its URL + to: [https://releases.jfrog.io/artifactory/oss-release-local/](https://releases.jfrog.io/artifactory/oss-release-local/) +* Make sure to configure the Artifactory server with the *jfrog-cli-remote* and *extractors* repositories in as a + [service connection](#Configuring-the-Service-Connections) in Azure DevOps of type *JFrog Artifactory V2*. +* Add the *JFrog Tools Installer* task to your build or release pipeline. +* Select the Artifactory service you configured. +* Select *jfrog-cli-remote* as the target repository to download the JFrog CLI. +* If your pipeline uses the [JFrog Maven](#jfrog-maven-task) or [JFrog Gradle](#jfrog-Gradle-task) tasks, select *extractors* as the repository to + download the Maven Extractor. ![tool-installer.png](images/tool-installer.png) @@ -172,7 +145,6 @@ configured to proxy the download repositories. #### Manual Installation - ##### Installing JFrog CLI @@ -186,9 +158,9 @@ To install JFrog CLI on an agent with no internet access: 1. Create the directory structure on your agent's `file-system: $(Agent.ToolsDirectory)/_jf/current/` 2. Download the latest JFrog CLI version from [here](https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf/). -3. Please make sure to download the executable matching your agent's operating system. Make sure to download the _jf_ - executable of JFrog CLI and not the legacy _jfrog_ executable. -4. Copy the downloaded _jf_ executable to the _current_ directory you created. +3. Please make sure to download the executable matching your agent's operating system. Make sure to download the *jf* + executable of JFrog CLI and not the legacy *jfrog* executable. +4. Copy the downloaded *jf* executable to the *current* directory you created. ##### Installing the Maven Extractor @@ -240,12 +212,12 @@ The build agent requires using Node.JS version 8 and above. To check which versi agent: 1. Navigate to the `Worker\Handlers\Node` folder located under the Agent home. -2. From the terminal, run _node -v_ +2. From the terminal, run *node -v* To upgrade Node.JS on the build agent: -- Replace the existing node.exe file on the agent with the node.exe file with the required version located in - the `Worker\Handlers\Node` folder under the agent home. +* Replace the existing node.exe file on the agent with the node.exe file with the required version located in + the `Worker\Handlers\Node` folder under the agent home.
@@ -254,12 +226,13 @@ To upgrade Node.JS on the build agent: To allow the JFrog tasks to work with your JFrog environment, you'll need to configure the following service connections in Azure DevOps. -| Service connection | Used by tasks | -| :---------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| | JFrog CLI V2 | -| | JFrog Tools Installer
JFrog Generic Artifacts
JFrog Nuget
JFrog .NET Core
JFrog npm
JFrog Pip
JFrog Maven
JFrog Gradle
JFrog Go
JFrog Conan
JFrog Collect Build Issues
JFrog Discard Builds
JFrog Build Promotion
JFrog Publish Build Info | -| | JFrog Audit
JFrog Build Scan | -| | JFrog Distribution | +| Service connection | Used by tasks | +|:-----------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| | JFrog CLI V2 | +| | JFrog Tools Installer
JFrog Generic Artifacts
JFrog Nuget
JFrog .NET Core
JFrog npm
JFrog Pip
JFrog Maven
JFrog Gradle
JFrog Go
JFrog Conan
JFrog Collect Build Issues
JFrog Discard Builds
JFrog Build Promotion
JFrog Publish Build Info | +| | JFrog Audit
JFrog Build Scan | +| | JFrog Distribution | +
Not Using a Public CA (Certificate Authority)? @@ -273,7 +246,6 @@ is under JFrog CLI's home directory. The home directory default location is `$(Agent.ToolsDirectory)/_jf/` Read more about this in the [JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli). -
@@ -291,133 +263,8 @@ To enable TLS 1.2 on TFS:
-
- -## Using OpenID Connect (OIDC) Authentication - -Using OpenID Connect (OIDC) to authenticate your pipelines eliminates the need for long lived static credentials providing a whole range of [security and practical benefits](https://jfrog.com/help/r/jfrog-platform-administration-documentation/openid-connect-integration-benefits). -You can read more about the [JFrog OpenID Connection Integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/openid-connect-integration) in the documentation. - -Setting up OpenID Connect has 3 separate parts: -- Setting up an OpenID Connect Integration inside of the JFrog Platform. -- Configuring Identity Mappings with Claim rules, matching to Projects & Service Connections. -- Configuring Service Connections as OpenID Connect in the Projects in your Azure Devops Instance. - -Follow the guides below to configure each part. - -
- - -#### Configure OpenID Connect Integration - - - - -First you must configure your JFrog instance to have an OpenID Connect integration to your Azure DevOps server. -Login to your JFrog instance as an Administrator, then as [described in the documentation:](https://jfrog.com/help/r/jfrog-platform-administration-documentation/openid-connect-configurations-overview) - -1. Go to the Administrator panel. -2. Select General Management. -3. Choose Manage Integrations. -4. Select New Integration - OpenID Connect - -Now fill out the integration with the parameters of your Azure DevOps instance. - -| Property name | Description | -| ------------- | --------------------------------------------------------------------------------------- | -| Provider Name | A name for your provider, this name is used in the Azure DevOps tasks in the pipelines. | -| Provider Type | Must be set to `Generic OpenID Connect` | -| Description | A description of what this provider is for. | -| Provider URL | `https://vstoken.dev.azure.com/{ORG_GUID}` (see how to get the {ORG_GUID} below). | -| Audience | Must be set to `api://AzureADTokenExchange`. | -| Token Issuer | If the issuer is different from the provider, for Azure DevOps this can be left blank. | - -As an example the final integration configuration will look like: - -![oidc-integration.png](images/oidc-integration.png) - -In order to obtain your Azure DevOps Organization GUID (`{ORG_GUID}`) you can simply run a pipeline in your Azure DevOps organization using any of the JFrog Task setup using a Service Connection configured with the `OpenID Connect Integration` authentication method, see the [Configure the Service Connection](#configure-the-service-connection) section. Even if the task fails due to you not yet having configured the Integration in JFrog, it will output the relevant information as part of the pipeline. - -In the Pipeline Output, look for the `OIDC Token Issuer`, this value is what you must put in as your `Provider URL`. -The rest of the information can also be helpful for you to configure the Identity Mappings as described in the section below. - -``` -OIDC Token Subject: sc://// -OIDC Token Claims: {"sub": "sc:////"} -OIDC Token Issuer: https://vstoken.dev.azure.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -OIDC Token Audience: api://AzureADTokenExchange -``` -
- -
- - -#### Configure Identity Mappings - - - -When the `OpenID Connect Integration` has been configured, you must now configure `Identity Mappings` for your projects and service connections to allow them to utilize the integration. -You can find the full documentation for configuring [Identity Mappings in the Documentation](https://jfrog.com/help/r/jfrog-platform-administration-documentation/identity-mappings). -For this part we will focus on how to setup the JSON Claim which is used to map the JWT request of the pipeline to the access rights in your mapping. - -When working with OpenID Connect, we must look at the `ID Token` that our provider (Azure DevOps) outputs. -Based on the information in the token, we can map properties into rules in our `Identity Mappings` JSON Claim. -The `ID Token` from the Azure DevOps token provider looks like this: - -```json -{ - "jti": "", - "sub": "sc:////", - "aud": "api://AzureADTokenExchange", - "iss": "https://vstoken.dev.azure.com/", - "nbf": 1708639268, - "exp": 1708640467, - "iat": 1708639868 -} -``` -Relative to most other `ID Token` providers, our options are fairly sparse, the only sensible option is using the subject (`"sub"`) field. -The claim mapping does support wildcards with the `*` operator. - -A sample JSON Claim mapping which maps a specified ServiceConnection in a specified Project in your Organization would look like this: - -```json -{ "sub": "sc://MyOrg/MyProject/MyServiceConnection" } -``` -![oidc-json-mapping.png](images/oidc-json-mapping.png) - -To allow all projects in your Organization with a ServiceConnection with a specified name, you could replace MyProject with `*`. -Just make sure to never replace your Organization name with a `*` operator as that would allow any Azure DevOps Organization to gain access to your instance. - -
- -
- - -#### Configure the Service Connection - - - -You must configure a `ServiceConnection` setting the `Authentication method` to `OpenID Connect Integration`. -All four types of Service Connections are supported, they will all require the same input regardless of the type. - -This requires you to fill in the following inputs: - -| Property name | Description | -| ---------------------------- | ------------------------------------------------------------------------------------------------------ | -| Server URL | The URL of your JFrog instance with the `/artifactory` path fx. (`https://my.jfrog.io/artifactory`) | -| OpenID Connect Provider Name | The `Provider Name` you configured in the `Configure OpenID Connect Integration` step | -| Platform URL | The URL of your JFrog instance fx. (`https://my.jfrog.io/`) | -| Service connection name | The name of the Service Connection, must match the values put into the `JSON Claims mapping` | -| Description (optional) | A short of the purpose of this ServiceConnection | - -A sample configuration would look like this: - -![oidc-service-connection.png](images/oidc-service-connection.png) - -Now this Service Connection can be used for any of JFrog tasks as normal, authenticating with a temporary access token each time the pipeline runs. - -
+
## Executing JFrog CLI Commands @@ -425,12 +272,11 @@ Now this Service Connection can be used for any of JFrog tasks as normal, authen #### JFrog CLI V2 Task - -The extension support a generic [JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli) task, named _JFrog CLI V2_, -which allows executing _[JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli)_ commands. -The command will use the connection details provided by the selected _JFrog Platform_ service connection configured in +The extension support a generic [JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli) task, named *JFrog CLI V2*, +which allows executing *[JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli)* commands. +The command will use the connection details provided by the selected *JFrog Platform* service connection configured in Azure DevOps, so there's no need to provide the connection details as command options. @@ -447,8 +293,8 @@ Single command example: inputs: jfrogPlatformConnection: 'JFrog Platform V2' command: | - jf go-config --repo-resolve=go-remote --repo-deploy=go-local - jf go build + jf go-config --repo-resolve=go-remote --repo-deploy=go-local + jf go build jf go-publish v1.0.0 jf rt bce $(Build.DefinitionName) $(Build.BuildNumber) jf rt build-publish $(Build.DefinitionName) $(Build.BuildNumber) @@ -462,12 +308,13 @@ Multiple commands example: jfrogPlatformConnection: 'JFrog Platform V2' command: | jf rt ping - jf terraform-config --repo-deploy=terraform-remote + jf terraform-config --repo-deploy=terraform-remote jf terraform publish --namespace=example --provider=aws --tag=v0.0.1 ```
+
## Managing Generic Artifacts @@ -475,24 +322,24 @@ Multiple commands example:
JFrog Generic Artifacts task -The _JFrog Generic Artifacts_ task supports following operations with JFrog Artifactory: +The *JFrog Generic Artifacts* task supports following operations with JFrog Artifactory: -- Uploading artifacts to Artifactory -- Downloading artifacts from Artifactory -- Copying artifacts in Artifactory -- Moving artifacts in Artifactory -- Deleting artifacts in Artifactory -- Setting properties on artifacts in Artifactory -- Deleting properties from artifacts in Artifactory +* Uploading artifacts to Artifactory +* Downloading artifacts from Artifactory +* Copying artifacts in Artifactory +* Moving artifacts in Artifactory +* Deleting artifacts in Artifactory +* Setting properties on artifacts in Artifactory +* Deleting properties from artifacts in Artifactory The task triggers [JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli) to perform these actions using [File Specs](https://jfrog.com/help/r/jfrog-integrations-documentation/using-file-specs). When the task is used for uploading and downloading artifacts, it can also be configured to capture the build-info, -which can be later published to Artifactory using the _JFrog Publish Build Info_ task. +which can be later published to Artifactory using the *JFrog Publish Build Info* task. When configuring the task, do the following: -1. Select your configured _JFrog Artifactory V2_ service connection. +1. Select your configured *JFrog Artifactory V2* service connection. 2. Specify whether you'd like define the File Spec through the task UI or have the task read the spec from a file. @@ -500,11 +347,11 @@ When configuring the task, do the following: 4. Set the other task options. -5. Check the _Advanced_ section for additional options. +5. Check the *Advanced* section for additional options. ### Generic artifacts handling -The _JFrog Generic Artifacts_ task allows performing generic actions on artifacts, such as: +The *JFrog Generic Artifacts* task allows performing generic actions on artifacts, such as: 1. Downloading and uploading from/to Artifactory 2. Setting or deleting properties on artifacts in Artifactory @@ -517,7 +364,7 @@ The downloaded dependencies are defined using [File Specs](https://jfrog.com/help/r/jfrog-integrations-documentation/using-file-specs) and can be also configured to capture the build-info. It will store the downloaded files as dependencies in the build-info which can later be published to Artifactory using -the _JFrog Publish Build-Info_ task. +the *JFrog Publish Build-Info* task. ![GenericDownload](images/marketplace/generic-download.png) @@ -527,7 +374,7 @@ The task also supports uploading your generated build artifacts from the build a The artifacts are defined using [File Specs](https://jfrog.com/help/r/jfrog-integrations-documentation/using-file-specs). The task can be also configured to capture build-info and stores the uploaded files as artifacts in the build-info. The -captured build-info can be later published to Artifactory using the _JFrog Publish Build-Info_ task. +captured build-info can be later published to Artifactory using the *JFrog Publish Build-Info* task. ![GenericUpload](images/marketplace/generic-upload.png) @@ -570,25 +417,26 @@ YAML Example:
+
## Build tools Tasks +
- + #### JFrog Maven Task - ![mvn.png](images/marketplace/mvn.png) -The _JFrog Maven_ task allows triggering Maven builds, while resolving dependencies and deploying artifacts from and +The *JFrog Maven* task allows triggering Maven builds, while resolving dependencies and deploying artifacts from and to Artifactory. -The task uses the configured _JFrog Artifactory V2_ service connection. +The task uses the configured *JFrog Artifactory V2* service connection. The task can also be configured to capture build-info and store the downloaded and uploaded artifacts as build dependencies and build artifacts. -The captured build-info can be later published to Artifactory using the _[JFrog Publish Build-Info](#jfrog-publish-build-info)_ task. +The captured build-info can be later published to Artifactory using the *[JFrog Publish Build-Info](#JFrog-Publish-Build-Info)* task. ![mvn.png](images/maven-task.png) @@ -620,35 +468,33 @@ The patterns can include wildcards and should be separated by a comma followed b For more information about Maven repositories, see [Artifactory Maven Repository](https://jfrog.com/help/r/jfrog-artifactory-documentation/maven-repository) -
- + #### JFrog Gradle Task - ![gradle.png](images/marketplace/gradle.png) -The _JFrog Gradle_ task allows triggering Gradle builds, while resolving dependencies and deploying artifacts from and +The *JFrog Gradle* task allows triggering Gradle builds, while resolving dependencies and deploying artifacts from and to Artifactory. -The task uses the configured _JFrog Artifactory V2_ service connection. +The task uses the configured *JFrog Artifactory V2* service connection. The task can also be configured to capture build-info and store the downloaded and uploaded artifacts as build dependencies and build artifacts. -The captured build-info can be later published to Artifactory using the _[JFrog Publish Build-Info](#jfrog-publish-build-info)_ task. +The captured build-info can be later published to Artifactory using the *[JFrog Publish Build-Info](#JFrog-Publish-Build-Info)* task. -Behind the scenes, the _JFrog Gradle_ task uses +Behind the scenes, the *JFrog Gradle* task uses the [Gradle Artifactory Plugin](https://jfrog.com/help/r/jfrog-integrations-documentation/gradle-artifactory-plugin) to integrate with the Gradle build. In case your Gradle script already applies the [Gradle Artifactory Plugin](https://jfrog.com/help/r/jfrog-integrations-documentation/gradle-artifactory-plugin), -set the _Use Artifactory Plugin_ option, to let the task know that it shouldn't apply the plugin in the Gradle script. +set the *Use Artifactory Plugin* option, to let the task know that it shouldn't apply the plugin in the Gradle script. -You should set _artifactoryPublish_ as one of the Gradle tasks in the task(s) fields. -_artifactoryPublish_ is a task that is exposed by the Gradle Artifactory Plugin, and is used for deploying artifacts +You should set *artifactoryPublish* as one of the Gradle tasks in the task(s) fields. +*artifactoryPublish* is a task that is exposed by the Gradle Artifactory Plugin, and is used for deploying artifacts as well as publishing build-info to Artifactory. ![gradle.png](images/gradle-task.png) @@ -667,20 +513,19 @@ as well as publishing build-info to Artifactory.
- + #### JFrog Npm Task - ![npm.png](images/marketplace/npm.png) -The _JFrog Npm_ task allows triggering npm builds, while resolving npm dependencies and deploying npm packages from +The *JFrog Npm* task allows triggering npm builds, while resolving npm dependencies and deploying npm packages from and to Artifactory. -The task uses the configured _JFrog Artifactory V2_ service connection. +The task uses the configured *JFrog Artifactory V2* service connection. The task can be also configured to capture build-info and store the uploaded files as artifacts in it. -The captured build-info can be later published to Artifactory using the _[JFrog Publish Build-Info](#jfrog-publish-build-info)_ task. +The captured build-info can be later published to Artifactory using the *[JFrog Publish Build-Info](#JFrog-Publish-Build-Info)* task. ![npm.png](images/npm-task.png) @@ -703,20 +548,20 @@ see [Artifactory npm Registry](https://jfrog.com/help/r/jfrog-artifactory-docume
- + #### JFrog Nuget and .NET Core Task - + ![nuget.png](images/marketplace/nuget.png) -The _JFrog Nuget_ and _JFrog .NET Core_ tasks allow restoring NuGet packages from Artifactory. +The *JFrog Nuget* and *JFrog .NET Core* tasks allow restoring NuGet packages from Artifactory. These tasks also allow publishing NuGet packages to Artifactory. -The task uses the configured _JFrog Artifactory V2_ service connection. +The task uses the configured *JFrog Artifactory V2* service connection. The tasks can be configured to capture build-info. The build-info stores the restored packages as build dependencies and uploaded packages as build artifacts. -The captured build-info can be later published to Artifactory using the _[JFrog Publish Build-Info](#jfrog-publish-build-info)_ task. +The captured build-info can be later published to Artifactory using the *[JFrog Publish Build-Info](#JFrog-Publish-Build-Info)* task. ![nuget.png](images/nuget-task.png) @@ -735,20 +580,18 @@ The captured build-info can be later published to Artifactory using the _[JFrog For more information about Nuget repositories, see [Artifactory NuGet Repositories](https://jfrog.com/help/r/jfrog-artifactory-documentation/nuget-repositories) -
- + #### JFrog Pip Task - ![pip.png](images/marketplace/pip.png) -The _JFrog Pip_ task allows installing Pip packages from Artifactory. -The task uses the configured _JFrog Artifactory V2_ service connection. +The *JFrog Pip* task allows installing Pip packages from Artifactory. +The task uses the configured *JFrog Artifactory V2* service connection. The tasks can also be configured to capture build-info. The build-info stores the installed packages as build dependencies. The captured build-info can be later published to Artifactory using @@ -767,17 +610,17 @@ the [Publishing Build Info to Artifactory](http://www.jfrog.com#PublishingBuildI buildNumber: '$(Build.BuildNumber)' ``` -_Recording all dependencies as part of the build-info_ -When running the _JFrog Pip_ task inside a Python environment, which already has some of the packages installed, the +*Recording all dependencies as part of the build-info* +When running the *JFrog Pip* task inside a Python environment, which already has some of the packages installed, the installed packages will not be included as part of the build-info, if they were not originally installed from Artifactory. A warning message will be added to the build log in this case. -_How to include all packages in the build-info?_ -Running the task for the first time with the _Disable local pip cache_ option checked, +*How to include all packages in the build-info?* +Running the task for the first time with the *Disable local pip cache* option checked, should re-download and install these packages, and they will therefore be included in the build-info. It is also recommended to run the command from inside a [virtual environment](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/). -The _Virtual environment setup command_ field allows this. +The *Virtual environment setup command* field allows this. ![pip-advanced.png](images/pip-advanced.png) @@ -788,26 +631,25 @@ included in the build-info, even if they are already cached locally.
- + #### JFrog Conan Task - ![conan.png](images/marketplace/conan.png) [Conan](https://conan.io/) is a package manager for C and C++. -The _JFrog Conan_ task allows triggering a conan build while resolving conan dependencies from a conan repository in +The *JFrog Conan* task allows triggering a conan build while resolving conan dependencies from a conan repository in Artifactory. -The task uses the configured _JFrog Artifactory V2_ service connection. +The task uses the configured *JFrog Artifactory V2* service connection. It also allows publishing conan packages to an Artifactory conan repository. The task can be also configured to capture build-info and store the downloaded and uploaded packages as build dependencies and artifact. -The captured build-info can be later published to Artifactory using the _[JFrog Publish Build-Info](#jfrog-publish-build-info)_ task. +The captured build-info can be later published to Artifactory using the *[JFrog Publish Build-Info](#JFrog-Publish-Build-Info)* task. -The task supports the _config install_ , _add remote_ , _create_ and _upload_ conan commands. -In addition, it supports a _custom_ option, allowing to configure the task to execute any conan command. +The task supports the *config install* , *add remote* , *create* and *upload* conan commands. +In addition, it supports a *custom* option, allowing to configure the task to execute any conan command. The full documentation of Conan is available at the [conan website](https://docs.conan.io/en/latest/). ![conan.png](images/conan-task.png) @@ -823,22 +665,20 @@ The full documentation of Conan is available at the [conan website](https://docs For more information about Conan repositories, see [Artifactory Conan Repositories](https://jfrog.com/help/r/jfrog-artifactory-documentation/conan-repositories) -
- + #### JFrog Go Task - -The _JFrog Go_ task allows triggering a go build, while resolving go dependencies from a go repository in Artifactory. -The task uses the configured _JFrog Artifactory V2_ service connection. +The *JFrog Go* task allows triggering a go build, while resolving go dependencies from a go repository in Artifactory. +The task uses the configured *JFrog Artifactory V2* service connection. It also allows publishing go packages to an Artifactory go repository. The task can be also configured to capture build-info and store the downloaded and uploaded packages as build dependencies and artifact. -The captured build-info can be later published to Artifactory using the _JFrog Publish Build-Info_ task. +The captured build-info can be later published to Artifactory using the *JFrog Publish Build-Info* task. ![go.png](images/go-task.png) @@ -857,26 +697,26 @@ The captured build-info can be later published to Artifactory using the _JFrog P For more information about Go repositories, see [Artifactory Go Repositories](https://jfrog.com/help/r/jfrog-artifactory-documentation/go-registry) -
+
## Build Tasks +
- + #### JFrog Collect Build Issues - Being able to look at the build which was published to Artifactory, and see all JIRA issues associated with it, is one of the most powerful capabilities of Artifactory when it comes to managing metadata about artifacts builds. -The _JFrog Collect Build Issues_ task collects the list of tracked project issues (for example, issues stored in JIRA, +The *JFrog Collect Build Issues* task collects the list of tracked project issues (for example, issues stored in JIRA, GitHub or any other bug tracking systems, and adds these issues to the build-info. -The task uses the configured _JFrog Artifactory V2_ service connection. The issues are collected by reading the git +The task uses the configured *JFrog Artifactory V2* service connection. The issues are collected by reading the git commit messages from the local git log. Each commit message is matched against a pre-configured regular expression, which retrieves the issue ID and issue summary. @@ -902,7 +742,7 @@ issues: ##### Configuration properties | Property name | Description | -| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Version | The schema version is intended for internal use. Do not change! | | trackerName | The name (type) of the issue tracking system. For example, JIRA. This property can take any value. | | regexp | A regular expression used for matching the git commit messages. The expression should include two capturing groups - for the issue key (ID) and the issue summary. In the example above, the regular expression matches the commit messages as displayed in the following example:
HAP-1007 - This is a sample issue | @@ -919,15 +759,14 @@ It can then be accesses and used by this task.
- + #### JFrog Publish Build Info - Most of the JFrog tasks can be configured to collect and store build-info locally. -The task uses the configured _JFrog Artifactory V2_ service connection. -The collected build info can be then published to Artifactory using the _JFrog Publish Build Info_ task. +The task uses the configured *JFrog Artifactory V2* service connection. +The collected build info can be then published to Artifactory using the *JFrog Publish Build Info* task. For more information about Build Info, see [Artifactory Build Integration](https://jfrog.com/help/r/jfrog-cli/build-integration) @@ -945,7 +784,7 @@ collect environment variables from the agent and add them to the build-info. excludeEnvVars: '*password*;*psw*;*secret*;*key*;*token*;*auth*;' ``` -After the build-info is published to Artifactory, it can be accessed from the _Artifactory_ tab in the Build Results. +After the build-info is published to Artifactory, it can be accessed from the *Artifactory* tab in the Build Results. ![build-results.png](images/marketplace/build-results.png) ![bi-in-artifactory.png](images/marketplace/bi-in-artifactory.png) @@ -953,36 +792,36 @@ After the build-info is published to Artifactory, it can be accessed from the _A
- + #### JFrog Build Promotion - + To support the artifacts life-cycle, Artifactory supports promoting published builds from one repository to another. -The _JFrog Build Promotion_ task promotes a build, by either copying or moving the build artifacts and/or dependencies +The *JFrog Build Promotion* task promotes a build, by either copying or moving the build artifacts and/or dependencies to a target repository. This task can be added as part of a Build or Release pipeline. -Run these steps to configure the _JFrog Build Promotion_ task: +Run these steps to configure the *JFrog Build Promotion* task: -1. Select the configured _JFrog Artifactory V2_ service connection, to which the build has been published. +1. Select the configured *JFrog Artifactory V2* service connection, to which the build has been published. -2. Specify the name of a*target repository* to which the build should be promoted. +2. Specify the name of a* target repository* to which the build should be promoted. -3. Set the _status_ of the build and optionally add a _Comment_. These details will be visible as part of the Build +3. Set the *status* of the build and optionally add a *Comment*. These details will be visible as part of the Build History in the Artifactory UI. -4. (Optional) Set a _source repository_ for the promotion. +4. (Optional) Set a *source repository* for the promotion. -5. Select the _include build dependencies_ if you want the build dependencies to be promoted. +5. Select the *include build dependencies* if you want the build dependencies to be promoted. -6. To copy and not to move the artifacts to the target repository, select the _Use copy_ option to copy the artifacts +6. To copy and not to move the artifacts to the target repository, select the *Use copy* option to copy the artifacts to the target repository. -7. Select _Dry run_ to test the promotion prior to running the build promotion. +7. Select *Dry run* to test the promotion prior to running the build promotion. ![build-promotion.png](images/marketplace/build-promotion.png) @@ -1005,24 +844,24 @@ Run these steps to configure the _JFrog Build Promotion_ task: You can control the life cycle of your artifacts by promoting them from one Artifactory repository to another. Build Promotion can come in handy when embedding it as part of release pipeline in Azure DevOps. -To help you achieve this, follow these steps for creating a release which includes the _JFrog Build Promotion_ task. +To help you achieve this, follow these steps for creating a release which includes the *JFrog Build Promotion* task. 1. Create a new Release. ![promotion.png](images/promotion1.png) -2. Click _environment_ and select a template for the release. +2. Click *environment* and select a template for the release. ![promotion.png](images/promotion2.png) -3. Click _Artifact_ and select _Build_ as the source type. +3. Click *Artifact* and select *Build* as the source type. 4. Fill out the rest of the form details. 5. If you'd like this release to always use the latest build from Artifactory, select specify a specific build number - as the _Default version_ and select one of the available build number i the _Build number_ list box. + as the *Default version* and select one of the available build number i the *Build number* list box. 6. If you'd like to promote a specific build number during the release, select specify at the time of release - creation as the _Default version_: + creation as the *Default version*: ![promotion.png](images/promotion3.png) -7. If you wish to promote the latest build number, select specify a specific build number as the _Default version_ - and then select _any_ build number. Then, click on the _Variables_ tab and add - the _ARTIFACTORY_RELEASE_BUILD_NUMBER_ pipeline variable with _LATEST_ as the value. +7. If you wish to promote the latest build number, select specify a specific build number as the *Default version* + and then select *any* build number. Then, click on the *Variables* tab and add + the *ARTIFACTORY_RELEASE_BUILD_NUMBER* pipeline variable with *LATEST* as the value. ![promotion.png](images/promotion4.png) -8. Configure the _Artifactory Build Promotion_ task as one of your release pipeline tasks. +8. Configure the *Artifactory Build Promotion* task as one of your release pipeline tasks. The task uses a build number which will be selected later on, upon creating a release. ![promotion.png](images/promotion5.png) 9. That's it, you're done! @@ -1033,17 +872,16 @@ To help you achieve this, follow these steps for creating a release which includ
- + #### Discarding Published Builds from Artifactory - -To discard old runs of a build from Artifactory, add the _JFrog Discard Builds_ task to the pipeline. +To discard old runs of a build from Artifactory, add the *JFrog Discard Builds* task to the pipeline. Run these steps to configure the task. -1. Select the configured _JFrog Artifactory V2_ service connection, on which you'd like the builds to be discarded. +1. Select the configured *JFrog Artifactory V2* service connection, on which you'd like the builds to be discarded. 2. Type the name of the build. @@ -1077,14 +915,14 @@ Run these steps to configure the task. ## JFrog Xray tasks
- + #### Audit project's dependencies for Security Vulnerabilities - -The _JFrog Audit_ task triggers an audit of your project dependencies for security vulnerabilities with JFrog Xray. -The task uses the configured _JFrog Xray V2_ service connection. + +The *JFrog Audit* task triggers an audit of your project dependencies for security vulnerabilities with JFrog Xray. +The task uses the configured *JFrog Xray V2* service connection. The scan is synchronous, meaning the tasks waits for the scan to finish. To determine the policy for identifying the vulnerabilities, you can either set a list for Xray Watches or select a JFrog Project or path in Artifactory associated with the policy. @@ -1106,18 +944,17 @@ JFrog Project or path in Artifactory associated with the policy.
- + #### Scanning Published Builds for Security Vulnerabilities - -The _JFrog Build Scan_ task allows triggering a build scan with JFrog Xray. -For the build to be scanned, it first needs to be published to Artifactory using the _[JFrog Publish Build-Info](#jfrog-publish-build-info)_ task. -The task uses the configured _JFrog Xray V2_ service connection. +The *JFrog Build Scan* task allows triggering a build scan with JFrog Xray. +For the build to be scanned, it first needs to be published to Artifactory using the *[JFrog Publish Build-Info](#JFrog-Publish-Build-Info)* task. +The task uses the configured *JFrog Xray V2* service connection. When the scan is triggered, Xray starts scanning the build artifacts and dependencies. The scan is synchronous, meaning the tasks waits for the scan to finish. -If the _Allow fail build_ task option is set and Xray is configured to fail the build, the build pipeline will fail, +If the *Allow fail build* task option is set and Xray is configured to fail the build, the build pipeline will fail, if vulnerabilities are found. > This functionality requires version 3.37.0 or above of JFrog Xray. @@ -1142,23 +979,23 @@ build-info report.
+
## JFrog Docker tasks
- + #### Pushing and Pulling Docker Images to and from Artifactory - -The _JFrog Docker_ task allows pushing and pulling docker images to and from a docker repository in Artifactory. +The *JFrog Docker* task allows pushing and pulling docker images to and from a docker repository in Artifactory. The task can be also configured to capture build-info for the pushed or pulled image. In addition to details about the build and the build environment, the build info includes the image layers as build dependencies and build artifacts. The task stores build info locally on the build agent. -The stored build-info can be later published to Artifactory using the _JFrog Publish Build Info_ task. +The stored build-info can be later published to Artifactory using the *JFrog Publish Build Info* task. > This functionality requires version 7.33.3 or above of Artifactory. @@ -1181,14 +1018,14 @@ see [Artifactory Docker Registry](https://jfrog.com/help/r/jfrog-artifactory-doc
+
- + #### Scanning Local Docker Images with JFrog Xray - -The _JFrog Docker_ task allows scanning local docker images using JFrog Xray. The scan results is displayed in the +The *JFrog Docker* task allows scanning local docker images using JFrog Xray. The scan results is displayed in the build log. By default, the result will include all vulnerabilities found. You may however configure the task to show only @@ -1220,10 +1057,12 @@ You do this by configuring the task to use:
+
## Using Published Artifacts in a Release + Artifacts which were published to Artifactory can be made available for a Release Pipeline. There are two ways to achieve this: @@ -1231,10 +1070,9 @@ There are two ways to achieve this: #### Using JFrog Generic Artifacts task - -The first way is to use the [JFrog Generic Artifacts](#managing-generic-artifacts) task to download the files during the +The first way is to use the [JFrog Generic Artifacts](#Managing-Generic-Artifacts) task to download the files during the release. Read more about this in the Downloading Generic Dependencies from Artifactory section. @@ -1244,7 +1082,6 @@ the Downloading Generic Dependencies from Artifactory section. #### Using Azure Artifact source - You can also set Artifactory as an artifact source for the release. @@ -1254,34 +1091,34 @@ Info to Artifactory section. Follow these steps to add Artifactory as an artifact source to a Release. -1. Create a new Release and click on _Artifacts Add_ +1. Create a new Release and click on *Artifacts Add* - ![release1.png](images/release1.png) + ![release1.png](images/release1.png) -2. Select the _Artifactory_ source type. +2. Select the *Artifactory* source type. - ![release2.png](images/release2.png) + ![release2.png](images/release2.png) 3. Select an Artifactory service, a build name, and the default version to use. - ![release3.png](images/release3.png) + ![release3.png](images/release3.png) - That's it! You're done. + That's it! You're done. - Now, when initiating the Release, the artifacts associated with the defined build are downloaded to the release - agent. + Now, when initiating the Release, the artifacts associated with the defined build are downloaded to the release + agent.
+
## Managing and Distributing Release Bundles
- + #### JFrog Distribution V2 Task - [JFrog Distribution](https://jfrog.com/help/r/jfrog-distribution-documentation) is a centralized platform that lets you @@ -1296,19 +1133,19 @@ As part of the release flow, release bundles are verified by the target destinat correctly and safe to use. JFrog DistributionDistributing Release Bundles -The _JFrog Distribution_ task allows creating, updating, signing and deleting release bundles. +The *JFrog Distribution* task allows creating, updating, signing and deleting release bundles. It also allows distributing the release to the edge nodes. -- The task requires configuring your _JFrog Distribution V2_ instance as a service connection in Azure DevOps. -- You can then set the instance you configured as the Distribution service value in the task. -- The task triggers [JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli) to execute the distribution actions. -- When creating or updating a release bundle, you need to - provide [File Specs](https://jfrog.com/help/r/jfrog-integrations-documentation/using-file-specs) defining the - artifacts to be included in the release bundle. -- When distributing a release bundle, you can control the distribution destinations by defining rules distribution rules - in a JSON format. +* The task requires configuring your *JFrog Distribution V2* instance as a service connection in Azure DevOps. +* You can then set the instance you configured as the Distribution service value in the task. +* The task triggers [JFrog CLI](https://jfrog.com/help/r/jfrog-cli/jfrog-cli) to execute the distribution actions. +* When creating or updating a release bundle, you need to + provide [File Specs](https://jfrog.com/help/r/jfrog-integrations-documentation/using-file-specs) defining the + artifacts to be included in the release bundle. +* When distributing a release bundle, you can control the distribution destinations by defining rules distribution rules + in a JSON format. -_Distribution Rules JSON structure_ Here's an example: +*Distribution Rules JSON structure* Here's an example: ```JSON { @@ -1363,10 +1200,12 @@ The Distribution Rules format also supports wildcards. For example:
+
## Contribution + We welcome pull requests from the community!
@@ -1378,7 +1217,6 @@ To build and run the extension sources, please follow these steps: 1. Clone the code from git. 2. To Build and create the JFrog Artifactory extension `vsix` file, run the following command. - ``` npm i npm run create @@ -1400,7 +1238,6 @@ Use the following commands to run from terminal: 1. Set the ADO_JFROG_PLATFORM_URL, ADO_JFROG_PLATFORM_USERNAME and ADO_JFROG_PLATFORM_PASSWORD environment variables with your JFrog Platform URL, username and password: - ``` export ADO_JFROG_PLATFORM_URL='https://myrepo.jfrog.io/' export ADO_JFROG_PLATFORM_USERNAME=admin @@ -1408,7 +1245,6 @@ Use the following commands to run from terminal: ``` 2. Run the following commands: - ``` npm i -g jfrog-cli-v2-jf npm t @@ -1419,10 +1255,10 @@ ts-node: `mocha -r ts-node/register tests.ts -t 1000000`. #### Skipping Tests -In order to skip tests, set the ADO*SKIP_TESTS environment variable with the tests you wish to skip, separated by +In order to skip tests, set the ADO_SKIP_TESTS environment variable with the tests you wish to skip, separated by commas. -The supported values are: \_maven*, _gradle_, _npm_, _go_, _nuget_, _dotnet_, _conan_, _pip_, _proxy_, -_distribution_, _unit_, _installer_ and _generic_. +The supported values are: *maven*, *gradle*, *npm*, *go*, *nuget*, *dotnet*, *conan*, *pip*, *proxy*, +*distribution*, *unit*, *installer* and *generic*. For example, for skipping the nuget and dotnet tests: @@ -1435,13 +1271,14 @@ export ADO_SKIP_TESTS=nuget,dotnet
Pull request guidelines -- Pull requests should be created on the _dev_ branch. -- Please make sure the code is covered by tests. -- Please run `npm run format` for formatting the code before submitting the pull request. -- Please run `npm run lint` and make sure no new tslint warnings were introduced. +* Pull requests should be created on the *dev* branch. +* Please make sure the code is covered by tests. +* Please run `npm run format` for formatting the code before submitting the pull request. +* Please run `npm run lint` and make sure no new tslint warnings were introduced.
## Reporting issues Please help us improve jfrog-azure-devops-extension by [reporting issues](https://github.com/jfrog/jfrog-azure-devops-extension/issues/new/choose) you encounter. + From 5d58e1178aa654953ffe7b70ee3b9616b6bed454 Mon Sep 17 00:00:00 2001 From: delarea Date: Mon, 14 Apr 2025 15:44:24 +0300 Subject: [PATCH 08/26] fix diff --- README.md | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/README.md b/README.md index be9bb02e..d00e55d9 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ The *[JFrog Extension](https://marketplace.visualstudio.com/items?itemName=JFrog - [Installing the Extension](#Installing-the-Extension) - [Installing the Build Agent](#Installing-the-Build-Agent) - [Configuring the Service Connections](#Configuring-the-Service-Connections) + - [Using OpenID Connect (OIDC) Authentication](#using-openid-connect-oidc-authentication) - [Executing JFrog CLI Commands](#Executing-JFrog-CLI-Commands) - [Build tools Tasks](#build-tools-tasks) - [JFrog Maven](#JFrog-Maven-Task) @@ -263,9 +264,136 @@ To enable TLS 1.2 on TFS:
+## Using OpenID Connect (OIDC) Authentication + +Using OpenID Connect (OIDC) to authenticate your pipelines eliminates the need for long lived static credentials providing a whole range of [security and practical benefits](https://jfrog.com/help/r/jfrog-platform-administration-documentation/openid-connect-integration-benefits). +You can read more about the [JFrog OpenID Connection Integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/openid-connect-integration) in the documentation. + +Setting up OpenID Connect has 3 separate parts: +- Setting up an OpenID Connect Integration inside of the JFrog Platform. +- Configuring Identity Mappings with Claim rules, matching to Projects & Service Connections. +- Configuring Service Connections as OpenID Connect in the Projects in your Azure Devops Instance. + +Follow the guides below to configure each part. + +
+ + +#### Configure OpenID Connect Integration + + + + +First you must configure your JFrog instance to have an OpenID Connect integration to your Azure DevOps server. +Login to your JFrog instance as an Administrator, then as [described in the documentation:](https://jfrog.com/help/r/jfrog-platform-administration-documentation/openid-connect-configurations-overview) + +1. Go to the Administrator panel. +2. Select General Management. +3. Choose Manage Integrations. +4. Select New Integration - OpenID Connect + +Now fill out the integration with the parameters of your Azure DevOps instance. + +| Property name | Description | +| ------------- | --------------------------------------------------------------------------------------- | +| Provider Name | A name for your provider, this name is used in the Azure DevOps tasks in the pipelines. | +| Provider Type | Must be set to `Generic OpenID Connect` | +| Description | A description of what this provider is for. | +| Provider URL | `https://vstoken.dev.azure.com/{ORG_GUID}` (see how to get the {ORG_GUID} below). | +| Audience | Must be set to `api://AzureADTokenExchange`. | +| Token Issuer | If the issuer is different from the provider, for Azure DevOps this can be left blank. | + +As an example the final integration configuration will look like: + +![oidc-integration.png](images/oidc-integration.png) + +In order to obtain your Azure DevOps Organization GUID (`{ORG_GUID}`) you can simply run a pipeline in your Azure DevOps organization using any of the JFrog Task setup using a Service Connection configured with the `OpenID Connect Integration` authentication method, see the [Configure the Service Connection](#configure-the-service-connection) section. Even if the task fails due to you not yet having configured the Integration in JFrog, it will output the relevant information as part of the pipeline. + +In the Pipeline Output, look for the `OIDC Token Issuer`, this value is what you must put in as your `Provider URL`. +The rest of the information can also be helpful for you to configure the Identity Mappings as described in the section below. + +``` +OIDC Token Subject: sc://// +OIDC Token Claims: {"sub": "sc:////"} +OIDC Token Issuer: https://vstoken.dev.azure.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +OIDC Token Audience: api://AzureADTokenExchange +``` +
+ +
+ + +#### Configure Identity Mappings + + + +When the `OpenID Connect Integration` has been configured, you must now configure `Identity Mappings` for your projects and service connections to allow them to utilize the integration. +You can find the full documentation for configuring [Identity Mappings in the Documentation](https://jfrog.com/help/r/jfrog-platform-administration-documentation/identity-mappings). +For this part we will focus on how to setup the JSON Claim which is used to map the JWT request of the pipeline to the access rights in your mapping. + +When working with OpenID Connect, we must look at the `ID Token` that our provider (Azure DevOps) outputs. +Based on the information in the token, we can map properties into rules in our `Identity Mappings` JSON Claim. +The `ID Token` from the Azure DevOps token provider looks like this: + +```json +{ + "jti": "", + "sub": "sc:////", + "aud": "api://AzureADTokenExchange", + "iss": "https://vstoken.dev.azure.com/", + "nbf": 1708639268, + "exp": 1708640467, + "iat": 1708639868 +} +``` +Relative to most other `ID Token` providers, our options are fairly sparse, the only sensible option is using the subject (`"sub"`) field. +The claim mapping does support wildcards with the `*` operator. + +A sample JSON Claim mapping which maps a specified ServiceConnection in a specified Project in your Organization would look like this: + +```json +{ "sub": "sc://MyOrg/MyProject/MyServiceConnection" } +``` +![oidc-json-mapping.png](images/oidc-json-mapping.png) + +To allow all projects in your Organization with a ServiceConnection with a specified name, you could replace MyProject with `*`. +Just make sure to never replace your Organization name with a `*` operator as that would allow any Azure DevOps Organization to gain access to your instance. + +
+ +
+ + +#### Configure the Service Connection + + + +You must configure a `ServiceConnection` setting the `Authentication method` to `OpenID Connect Integration`. +All four types of Service Connections are supported, they will all require the same input regardless of the type. + +This requires you to fill in the following inputs: + +| Property name | Description | +| ---------------------------- | ------------------------------------------------------------------------------------------------------ | +| Server URL | The URL of your JFrog instance with the `/artifactory` path fx. (`https://my.jfrog.io/artifactory`) | +| OpenID Connect Provider Name | The `Provider Name` you configured in the `Configure OpenID Connect Integration` step | +| Platform URL | The URL of your JFrog instance fx. (`https://my.jfrog.io/`) | +| Service connection name | The name of the Service Connection, must match the values put into the `JSON Claims mapping` | +| Description (optional) | A short of the purpose of this ServiceConnection | + +A sample configuration would look like this: + +![oidc-service-connection.png](images/oidc-service-connection.png) + +Now this Service Connection can be used for any of JFrog tasks as normal, authenticating with a temporary access token each time the pipeline runs. + +
+
+ + ## Executing JFrog CLI Commands
From 2bc3e5638b6ef7228012fbf8c46c585f9993f181 Mon Sep 17 00:00:00 2001 From: delarea Date: Wed, 16 Apr 2025 13:04:12 +0300 Subject: [PATCH 09/26] Refactor --- jfrog-tasks-utils/package.json | 5 ++-- jfrog-tasks-utils/utils.js | 55 ++++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/jfrog-tasks-utils/package.json b/jfrog-tasks-utils/package.json index 8719b646..675d3f42 100644 --- a/jfrog-tasks-utils/package.json +++ b/jfrog-tasks-utils/package.json @@ -9,10 +9,9 @@ "typings": "utils.d.ts", "dependencies": { "azure-pipelines-task-lib": "4.5.0", - "azure-pipelines-tool-lib": "2.0.6", "azure-pipelines-tasks-java-common": "^2.219.1", - "typed-rest-client": "^1.8.11", - "sync-request": "^6.1.0" + "azure-pipelines-tool-lib": "2.0.6", + "typed-rest-client": "^1.8.11" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" diff --git a/jfrog-tasks-utils/utils.js b/jfrog-tasks-utils/utils.js index fee3fbad..453b7703 100644 --- a/jfrog-tasks-utils/utils.js +++ b/jfrog-tasks-utils/utils.js @@ -19,7 +19,8 @@ const buildAgent = 'jfrog-azure-devops-extension'; const customFolderPath = encodePath(join(jfrogFolderPath, 'current')); const customCliPath = encodePath(join(customFolderPath, fileName)); // Optional - Customized jfrog-cli path. const jfrogCliReleasesUrl = 'https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf'; -const request = require('sync-request'); +const HttpClient = require('typed-rest-client/HttpClient').HttpClient; + // Set by Tools Installer Task. This JFrog CLI version will be used in all tasks unless manual installation is used, // or a specific version was requested in a task. If not set, use the default CLI version. const pipelineRequestedCliVersionEnv = 'JFROG_CLI_PIPELINE_REQUESTED_VERSION_AZURE'; @@ -253,7 +254,7 @@ function configureXrayCliServer(xrayService, serverId, cliPath, buildDir) { return configureSpecificCliServer(xrayService, '--xray-url', serverId, cliPath, buildDir); } -function getADOIdToken(serviceConnectionID) { +async function fetchAzureOidcToken(serviceConnectionID) { const uri = tl.getVariable('System.CollectionUri'); const teamPrjID = tl.getVariable('System.TeamProjectId'); const hub = tl.getVariable('System.HostType'); @@ -262,24 +263,34 @@ function getADOIdToken(serviceConnectionID) { const apiVersion = '7.1-preview.1'; const url = `${uri}${teamPrjID}/_apis/distributedtask/hubs/${hub}/plans/${planID}/jobs/${jobID}/oidctoken?api-version=${apiVersion}&serviceConnectionId=${serviceConnectionID}`; + const token = tl.getVariable('System.AccessToken'); - try { - const response = request('POST', url, { - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${tl.getVariable('System.AccessToken')}`, - }, - }); - - if (response.statusCode !== 200) { - throw new Error(`HTTP request failed with status code ${response.statusCode}`); - } + if (!token) { + throw new Error('System.AccessToken is not available. Make sure "Allow scripts to access OAuth token" is enabled.'); + } + + const httpClient = new HttpClient('jfrog-azure-devops-extension'); + + const res = await httpClient.post(url, '', { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }); - const parsedResponse = JSON.parse(response.getBody('utf8')); - return parsedResponse.oidcToken; - } catch (error) { - throw new Error(`Failed to get or parse response: ${error.message}`); + if (res.message.statusCode !== 200) { + throw new Error(`OIDC token request failed: HTTP ${res.message.statusCode}`); } + + const body = await res.readBody(); + + /** @type {{ oidcToken?: string }} */ + const parsed = JSON.parse(body); + + if (!parsed.oidcToken) { + throw new Error('OIDC token not found in response body.'); + } + + tl.debug('Successfully fetched OIDC token from Azure DevOps.'); + return parsed.oidcToken; } function configureSpecificCliServer(service, urlFlag, serverId, cliPath, buildDir) { @@ -293,13 +304,13 @@ function configureSpecificCliServer(service, urlFlag, serverId, cliPath, buildDi let secretInStdinSupported = isStdinSecretSupported(); if (oidcProviderName) { - const idToken = getADOIdToken(service); - (cliCommand = cliJoin( + const idToken = fetchAzureOidcToken(service); + cliCommand = cliJoin( cliCommand, '--oidc-provider-name=' + (isWindows() ? quote(oidcProviderName) : singleQuote(oidcProviderName)), - '--oidc-provider-type=' + 'Azure', - )), - '--oidc-token-id=' + (isWindows() ? quote(idToken) : singleQuote(idToken)); + '--oidc-provider-type=Azure', + '--oidc-token-id=' + (isWindows() ? quote(idToken) : singleQuote(idToken)) + ); return executeCliCommand(cliCommand, buildDir, { stdinSecret }); } From a44ba87c4174edb7295f6766064613fc1a476bcc Mon Sep 17 00:00:00 2001 From: delarea Date: Thu, 17 Apr 2025 16:00:31 +0300 Subject: [PATCH 10/26] commit logs for debugging --- jfrog-tasks-utils/utils.js | 40 +++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/jfrog-tasks-utils/utils.js b/jfrog-tasks-utils/utils.js index 453b7703..ed2375d1 100644 --- a/jfrog-tasks-utils/utils.js +++ b/jfrog-tasks-utils/utils.js @@ -19,7 +19,7 @@ const buildAgent = 'jfrog-azure-devops-extension'; const customFolderPath = encodePath(join(jfrogFolderPath, 'current')); const customCliPath = encodePath(join(customFolderPath, fileName)); // Optional - Customized jfrog-cli path. const jfrogCliReleasesUrl = 'https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf'; -const HttpClient = require('typed-rest-client/HttpClient').HttpClient; +const syncRequest = require('sync-request'); // Set by Tools Installer Task. This JFrog CLI version will be used in all tasks unless manual installation is used, // or a specific version was requested in a task. If not set, use the default CLI version. @@ -254,7 +254,7 @@ function configureXrayCliServer(xrayService, serverId, cliPath, buildDir) { return configureSpecificCliServer(xrayService, '--xray-url', serverId, cliPath, buildDir); } -async function fetchAzureOidcToken(serviceConnectionID) { +function fetchAzureOidcToken(serviceConnectionID) { const uri = tl.getVariable('System.CollectionUri'); const teamPrjID = tl.getVariable('System.TeamProjectId'); const hub = tl.getVariable('System.HostType'); @@ -262,35 +262,31 @@ async function fetchAzureOidcToken(serviceConnectionID) { const jobID = tl.getVariable('System.JobId'); const apiVersion = '7.1-preview.1'; - const url = `${uri}${teamPrjID}/_apis/distributedtask/hubs/${hub}/plans/${planID}/jobs/${jobID}/oidctoken?api-version=${apiVersion}&serviceConnectionId=${serviceConnectionID}`; const token = tl.getVariable('System.AccessToken'); - if (!token) { throw new Error('System.AccessToken is not available. Make sure "Allow scripts to access OAuth token" is enabled.'); } - const httpClient = new HttpClient('jfrog-azure-devops-extension'); + const url = `${uri}${teamPrjID}/_apis/distributedtask/hubs/${hub}/plans/${planID}/jobs/${jobID}/oidctoken?api-version=${apiVersion}&serviceConnectionId=${serviceConnectionID}`; - const res = await httpClient.post(url, '', { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${token}` + const res = syncRequest('POST', url, { + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + } }); - if (res.message.statusCode !== 200) { - throw new Error(`OIDC token request failed: HTTP ${res.message.statusCode}`); + if (res.statusCode !== 200) { + throw new Error(`OIDC token request failed: HTTP ${res.statusCode}\nBody: ${res.getBody('utf8')}`); } - - const body = await res.readBody(); - - /** @type {{ oidcToken?: string }} */ - const parsed = JSON.parse(body); - - if (!parsed.oidcToken) { + const body = JSON.parse(res.getBody('utf8')); + console.info(body) + console.info(body.oidcToken) + if (!body.oidcToken) { throw new Error('OIDC token not found in response body.'); } - - tl.debug('Successfully fetched OIDC token from Azure DevOps.'); - return parsed.oidcToken; + console.info("end of functoin") + return body.oidcToken; } function configureSpecificCliServer(service, urlFlag, serverId, cliPath, buildDir) { @@ -302,7 +298,7 @@ function configureSpecificCliServer(service, urlFlag, serverId, cliPath, buildDi let cliCommand = cliJoin(cliPath, jfrogCliConfigAddCommand, quote(serverId), urlFlag + '=' + quote(serviceUrl), '--interactive=false'); let stdinSecret; let secretInStdinSupported = isStdinSecretSupported(); - + console.info("hello") if (oidcProviderName) { const idToken = fetchAzureOidcToken(service); cliCommand = cliJoin( @@ -316,7 +312,7 @@ function configureSpecificCliServer(service, urlFlag, serverId, cliPath, buildDi if (serviceAccessToken) { // Add access-token if required. - cliCommand = cliJoin(cliCommand, secretInStdinSupported ? '--access-token-stdin' : '--access-token=' + quote(serviceAccessToken)); + cliCommand = cliJoin(cliCommand, secretInStdinSupported ? '--access-token-saaatdin' : '--access-token=' + quote(serviceAccessToken)); stdinSecret = secretInStdinSupported ? serviceAccessToken : undefined; } else { // Add username and password. From 26f806e94c26301859eb81e7e2de03d09e498587 Mon Sep 17 00:00:00 2001 From: delarea Date: Wed, 23 Apr 2025 13:51:48 +0300 Subject: [PATCH 11/26] Working eot but need to remove print --- jfrog-tasks-utils/utils.d.ts | 3 +- jfrog-tasks-utils/utils.js | 70 ++++++++++++++++++++++++++++-------- package.json | 3 ++ 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/jfrog-tasks-utils/utils.d.ts b/jfrog-tasks-utils/utils.d.ts index e825dc9f..24505787 100644 --- a/jfrog-tasks-utils/utils.d.ts +++ b/jfrog-tasks-utils/utils.d.ts @@ -41,6 +41,7 @@ declare module '@jfrog/tasks-utils' { export function removeExtractorsDownloadVariables(cliPath: string, workDir: string); export function configureArtifactoryCliServer(artifactoryService: string, serverId: string, cliPath: string, buildDir: string); export function setJdkHomeForJavaTasks(); - + export function fetchAzureOidcToken(serviceConnectionID: string) : string; + export function exchangeOidcTokenAndSetStepVariables(service:service,serviceUrl:string, oidcProviderName:string,cliPath:string, buildDir:string):string; export { taskSelectedCliVersionEnv }; } diff --git a/jfrog-tasks-utils/utils.js b/jfrog-tasks-utils/utils.js index ed2375d1..c3a2ae82 100644 --- a/jfrog-tasks-utils/utils.js +++ b/jfrog-tasks-utils/utils.js @@ -272,23 +272,66 @@ function fetchAzureOidcToken(serviceConnectionID) { const res = syncRequest('POST', url, { headers: { 'Content-Type': 'application/json', - 'Authorization': `Bearer ${token}` - } + Authorization: `Bearer ${token}`, + }, }); if (res.statusCode !== 200) { throw new Error(`OIDC token request failed: HTTP ${res.statusCode}\nBody: ${res.getBody('utf8')}`); } + /** @type {{ oidcToken?: string }} */ const body = JSON.parse(res.getBody('utf8')); - console.info(body) - console.info(body.oidcToken) if (!body.oidcToken) { throw new Error('OIDC token not found in response body.'); } - console.info("end of functoin") + const oidcClaims = JSON.parse(Buffer.from(body.oidcToken.split('.')[1], 'base64').toString()); + console.log('OIDC Token Subject: ', oidcClaims.sub); + console.log(`OIDC Token Claims: {"sub": "${oidcClaims.sub}"}`); + console.log('OIDC Token Issuer (Provider URL): ', oidcClaims.iss); + console.log('OIDC Token Audience: ', oidcClaims.aud); return body.oidcToken; } +function exchangeOidcTokenAndSetStepVariables(service, serviceUrl, oidcProviderName, cliPath, buildDir) { + let oidcAudience = tl.getEndpointAuthorizationParameter(service, 'oidcAudience', true) || 'api://AzureADTokenExchange'; + const repoName = tl.getVariable('Build.Repository.Name'); + const idToken = fetchAzureOidcToken(service); + + // Build the CLI command + let cliCommand = cliJoin( + cliPath, + `eot ${quote(oidcProviderName)} ${quote(idToken)} --url=${quote(serviceUrl)} --oidc-provider-type=Azure --oidc-audience=${quote(oidcAudience)} --repository=${quote(repoName)}` + ); + + let exeRes; + try { + // Execute the CLI command and capture the output + exeRes = executeCliCommand(cliCommand, buildDir, { withOutput: true }).toString(); + console.log('Exchange OIDC token result:', exeRes); + } catch (error) { + console.error('Error occurred while executing the CLI command:', error); + throw error; + } + + // Extract AccessToken + const accessTokenMatch = exeRes.match(/AccessToken:\s*([^\s]+)/); + const accessToken = accessTokenMatch ? accessTokenMatch[1] : null; + + // Extract Username + const usernameMatch = exeRes.match(/Username:\s*([^\s]+)/); + const username = usernameMatch ? usernameMatch[1] : null; + + if (!accessToken || !username) { + throw new Error('Failed to extract AccessToken or Username from the CLI output.'); + } + + // Set output variables + tl.setVariable('oidc_user', username, true); + tl.setVariable('oidc_token', accessToken, true); + + return accessToken; +} + function configureSpecificCliServer(service, urlFlag, serverId, cliPath, buildDir) { let serviceUrl = tl.getEndpointUrl(service, false); let serviceUser = tl.getEndpointAuthorizationParameter(service, 'username', true); @@ -298,21 +341,18 @@ function configureSpecificCliServer(service, urlFlag, serverId, cliPath, buildDi let cliCommand = cliJoin(cliPath, jfrogCliConfigAddCommand, quote(serverId), urlFlag + '=' + quote(serviceUrl), '--interactive=false'); let stdinSecret; let secretInStdinSupported = isStdinSecretSupported(); - console.info("hello") + + // In the case of OIDC, we exchange tokens via the CLI + // and populate the access token to the CLI config. + // This is done by the exchange command and not the config to export + // username and access token params for further use by the users. if (oidcProviderName) { - const idToken = fetchAzureOidcToken(service); - cliCommand = cliJoin( - cliCommand, - '--oidc-provider-name=' + (isWindows() ? quote(oidcProviderName) : singleQuote(oidcProviderName)), - '--oidc-provider-type=Azure', - '--oidc-token-id=' + (isWindows() ? quote(idToken) : singleQuote(idToken)) - ); - return executeCliCommand(cliCommand, buildDir, { stdinSecret }); + serviceAccessToken = exchangeOidcTokenAndSetStepVariables(service, serviceUrl, oidcProviderName, cliPath, buildDir); } if (serviceAccessToken) { // Add access-token if required. - cliCommand = cliJoin(cliCommand, secretInStdinSupported ? '--access-token-saaatdin' : '--access-token=' + quote(serviceAccessToken)); + cliCommand = cliJoin(cliCommand, secretInStdinSupported ? '--access-token-stdin' : '--access-token=' + quote(serviceAccessToken)); stdinSecret = secretInStdinSupported ? serviceAccessToken : undefined; } else { // Add username and password. diff --git a/package.json b/package.json index 2c29849c..1091e58e 100644 --- a/package.json +++ b/package.json @@ -26,5 +26,8 @@ "publish-private": "npm i --no-fund && bash buildScripts/publish-private.sh", "compile": "npx tsc -p ./", "lint": "npx eslint . --ext .ts,.tsx,.js" + }, + "dependencies": { + "sync-request": "^6.1.0" } } From 5034b6ff087029cea4593c7f5365d55dbd953d58 Mon Sep 17 00:00:00 2001 From: delarea Date: Wed, 23 Apr 2025 15:06:37 +0300 Subject: [PATCH 12/26] Export env vars --- jfrog-tasks-utils/utils.js | 72 ++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/jfrog-tasks-utils/utils.js b/jfrog-tasks-utils/utils.js index c3a2ae82..b21028ed 100644 --- a/jfrog-tasks-utils/utils.js +++ b/jfrog-tasks-utils/utils.js @@ -5,6 +5,7 @@ const execSync = require('child_process').execSync; const toolLib = require('azure-pipelines-tool-lib/tool'); const credentialsHandler = require('typed-rest-client/Handlers'); const findJavaHome = require('azure-pipelines-tasks-java-common/java-common').findJavaHome; +const syncRequest = require('sync-request'); const fileName = getCliExecutableName(); const jfrogCliToolName = 'jf'; @@ -19,7 +20,8 @@ const buildAgent = 'jfrog-azure-devops-extension'; const customFolderPath = encodePath(join(jfrogFolderPath, 'current')); const customCliPath = encodePath(join(customFolderPath, fileName)); // Optional - Customized jfrog-cli path. const jfrogCliReleasesUrl = 'https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf'; -const syncRequest = require('sync-request'); +const oidcUserOutputName = 'oidc_user'; +const oidcTokenOutputName = 'oidc_token'; // Set by Tools Installer Task. This JFrog CLI version will be used in all tasks unless manual installation is used, // or a specific version was requested in a task. If not set, use the default CLI version. @@ -284,11 +286,6 @@ function fetchAzureOidcToken(serviceConnectionID) { if (!body.oidcToken) { throw new Error('OIDC token not found in response body.'); } - const oidcClaims = JSON.parse(Buffer.from(body.oidcToken.split('.')[1], 'base64').toString()); - console.log('OIDC Token Subject: ', oidcClaims.sub); - console.log(`OIDC Token Claims: {"sub": "${oidcClaims.sub}"}`); - console.log('OIDC Token Issuer (Provider URL): ', oidcClaims.iss); - console.log('OIDC Token Audience: ', oidcClaims.aud); return body.oidcToken; } @@ -300,36 +297,57 @@ function exchangeOidcTokenAndSetStepVariables(service, serviceUrl, oidcProviderN // Build the CLI command let cliCommand = cliJoin( cliPath, - `eot ${quote(oidcProviderName)} ${quote(idToken)} --url=${quote(serviceUrl)} --oidc-provider-type=Azure --oidc-audience=${quote(oidcAudience)} --repository=${quote(repoName)}` + `eot ${quote(oidcProviderName)} ${quote(idToken)} --url=${quote(serviceUrl)} --oidc-provider-type=Azure --oidc-audience=${quote(oidcAudience)} --repository=${quote(repoName)}`, ); - let exeRes; - try { - // Execute the CLI command and capture the output - exeRes = executeCliCommand(cliCommand, buildDir, { withOutput: true }).toString(); - console.log('Exchange OIDC token result:', exeRes); - } catch (error) { - console.error('Error occurred while executing the CLI command:', error); - throw error; - } + // Execute the CLI command and capture the output + let exeRes = executeCliCommand(cliCommand, buildDir, { withOutput: true }).toString(); // Extract AccessToken - const accessTokenMatch = exeRes.match(/AccessToken:\s*([^\s]+)/); - const accessToken = accessTokenMatch ? accessTokenMatch[1] : null; + const { username, accessToken } = extractAccessTokenAndUsername(exeRes); - // Extract Username - const usernameMatch = exeRes.match(/Username:\s*([^\s]+)/); - const username = usernameMatch ? usernameMatch[1] : null; + // Set output variables + tl.setVariable(oidcUserOutputName, username, true); + tl.setVariable(oidcTokenOutputName, accessToken, true); + + return accessToken; +} - if (!accessToken || !username) { - throw new Error('Failed to extract AccessToken or Username from the CLI output.'); +/** + * Extracts AccessToken and Username from the CLI output. + * Supports both JSON and non-JSON (regex) outputs. + * Currently, the output is a non-valid JSON, which should be changed in the future. + * @param {string} output - The CLI output. + * @returns {{ accessToken: string, username: string }} - Extracted values. + * @throws {Error} - If neither JSON nor regex extraction succeeds. + */ +function extractAccessTokenAndUsername(output) { + // Attempt to parse as JSON + try { + const parsedOutput = JSON.parse(output); + if (parsedOutput.AccessToken && parsedOutput.Username) { + return { + accessToken: parsedOutput.AccessToken, + username: parsedOutput.Username, + }; + } + } catch (e) { + console.debug('Failed to parse output as JSON, trying with regex..'); } - // Set output variables - tl.setVariable('oidc_user', username, true); - tl.setVariable('oidc_token', accessToken, true); + // Fallback to regex extraction + const accessTokenMatch = output.match(/AccessToken:\s*(\S+)/); + const usernameMatch = output.match(/Username:\s*(\S+)/); - return accessToken; + if (accessTokenMatch && usernameMatch) { + return { + accessToken: accessTokenMatch[1], + username: usernameMatch[1], + }; + } + + // If both methods fail, throw an error + throw new Error('Failed to extract AccessToken or Username from the output.'); } function configureSpecificCliServer(service, urlFlag, serverId, cliPath, buildDir) { From 677a7ebd17aa413ab174d2a54256fa9ff07c3d60 Mon Sep 17 00:00:00 2001 From: delarea Date: Wed, 23 Apr 2025 16:17:15 +0300 Subject: [PATCH 13/26] Update --- README.md | 14 +++++++------- jfrog-tasks-utils/utils.js | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d00e55d9..1dc9be6b 100644 --- a/README.md +++ b/README.md @@ -294,14 +294,14 @@ Login to your JFrog instance as an Administrator, then as [described in the docu Now fill out the integration with the parameters of your Azure DevOps instance. -| Property name | Description | -| ------------- | --------------------------------------------------------------------------------------- | +| Property name | Description | +| ------------- |---------------------------------------------------------------------------| | Provider Name | A name for your provider, this name is used in the Azure DevOps tasks in the pipelines. | -| Provider Type | Must be set to `Generic OpenID Connect` | -| Description | A description of what this provider is for. | -| Provider URL | `https://vstoken.dev.azure.com/{ORG_GUID}` (see how to get the {ORG_GUID} below). | -| Audience | Must be set to `api://AzureADTokenExchange`. | -| Token Issuer | If the issuer is different from the provider, for Azure DevOps this can be left blank. | +| Provider Type | `Azure` | +| Description | A description of what this provider is for. | +| Provider URL | `https://vstoken.dev.azure.com/{ORG_GUID}` (see how to get the {ORG_GUID} below). | +| Audience | Must be set to `api://AzureADTokenExchange`. | +| Token Issuer | If the issuer is different from the provider, for Azure DevOps this can be left blank. | As an example the final integration configuration will look like: diff --git a/jfrog-tasks-utils/utils.js b/jfrog-tasks-utils/utils.js index b21028ed..9d9f5532 100644 --- a/jfrog-tasks-utils/utils.js +++ b/jfrog-tasks-utils/utils.js @@ -15,6 +15,7 @@ const defaultJfrogCliVersion = '2.75.0'; const minCustomCliVersion = '2.10.0'; const minSupportedStdinSecretCliVersion = '2.36.0'; const minSupportedServerIdEnvCliVersion = '2.37.0'; +const minSupportedOidcCliVersion = '2.75.0'; const pluginVersion = '2.10.4'; const buildAgent = 'jfrog-azure-devops-extension'; const customFolderPath = encodePath(join(jfrogFolderPath, 'current')); @@ -290,6 +291,12 @@ function fetchAzureOidcToken(serviceConnectionID) { } function exchangeOidcTokenAndSetStepVariables(service, serviceUrl, oidcProviderName, cliPath, buildDir) { + // First validate supported CLI version + if (getCliVersion(cliPath) < minSupportedOidcCliVersion) { + throw new Error( + `The CLI version ${getCliVersion(cliPath)} is not supported for OIDC token exchange. Minimum required version is ${minSupportedOidcCliVersion}.`, + ); + } let oidcAudience = tl.getEndpointAuthorizationParameter(service, 'oidcAudience', true) || 'api://AzureADTokenExchange'; const repoName = tl.getVariable('Build.Repository.Name'); const idToken = fetchAzureOidcToken(service); @@ -324,6 +331,13 @@ function exchangeOidcTokenAndSetStepVariables(service, serviceUrl, oidcProviderN function extractAccessTokenAndUsername(output) { // Attempt to parse as JSON try { + /** + * @typedef {Object} ParsedOutput + * @property {string} AccessToken + * @property {string} Username + */ + + /** @type {ParsedOutput} */ const parsedOutput = JSON.parse(output); if (parsedOutput.AccessToken && parsedOutput.Username) { return { From 42935aa1aaf69b00948113da15af461c4ce527d6 Mon Sep 17 00:00:00 2001 From: delarea Date: Wed, 23 Apr 2025 16:20:41 +0300 Subject: [PATCH 14/26] Allow bigger size --- buildScripts/publish-private.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) mode change 100644 => 100755 buildScripts/publish-private.sh diff --git a/buildScripts/publish-private.sh b/buildScripts/publish-private.sh old mode 100644 new mode 100755 index 0c1798a3..89a2519b --- a/buildScripts/publish-private.sh +++ b/buildScripts/publish-private.sh @@ -28,9 +28,10 @@ cp vss-extension.json vss-extension-private.json npx tfx extension unshare -t "$ADO_ARTIFACTORY_API_KEY" --extension-id jfrog-azure-devops-extension --publisher "$PUBLISHER" --unshare-with "$ADO_ARTIFACTORY_DEVELOPER" 2>/dev/null npx tfx extension unpublish -t "$ADO_ARTIFACTORY_API_KEY" --extension-id jfrog-azure-devops-extension --publisher "$PUBLISHER" npx tfx extension create --manifest-globs vss-extension-private.json --publisher "$PUBLISHER" -# Check that vsix size is less then 30MB + +# Max size is 50MB, but we want to be under 40. vsixSize="$(du -m -- *.vsix | awk '{print $1}' | head -1)" -if [ "${vsixSize}" -gt 30 ]; then +if [ "${vsixSize}" -gt 40 ]; then echo "Extension vsix size is greater than 30MB! (${vsixSize}MB) - Hint: Most of the dependencies on package-json are in format of - <^x.y.z>, so maybe one of them got updated, and the node_modules directory became bigger" exit 1 fi From d50c6fdbd89831cd73080f3d1926d1bff8db4892 Mon Sep 17 00:00:00 2001 From: delarea Date: Wed, 23 Apr 2025 16:34:47 +0300 Subject: [PATCH 15/26] add debug logs --- jfrog-tasks-utils/utils.js | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/jfrog-tasks-utils/utils.js b/jfrog-tasks-utils/utils.js index 9d9f5532..241e13da 100644 --- a/jfrog-tasks-utils/utils.js +++ b/jfrog-tasks-utils/utils.js @@ -6,6 +6,7 @@ const toolLib = require('azure-pipelines-tool-lib/tool'); const credentialsHandler = require('typed-rest-client/Handlers'); const findJavaHome = require('azure-pipelines-tasks-java-common/java-common').findJavaHome; const syncRequest = require('sync-request'); +import * as semver from 'semver'; const fileName = getCliExecutableName(); const jfrogCliToolName = 'jf'; @@ -257,6 +258,26 @@ function configureXrayCliServer(xrayService, serverId, cliPath, buildDir) { return configureSpecificCliServer(xrayService, '--xray-url', serverId, cliPath, buildDir); } +/** + * logging oidc token values for debugging + * @param oidcToken + */ +function debugLogIDToken(oidcToken) { + /** + * @typedef {Object} OidcClaims + * @property {string} sub - The subject of the token. + * @property {string} iss - The issuer of the token. + * @property {string} aud - The audience of the token. + */ + + /** @type {OidcClaims} */ + const oidcClaims = JSON.parse(Buffer.from(oidcToken.split('.')[1], 'base64').toString()); + console.debug('OIDC Token Subject: ', oidcClaims.sub); + console.debug(`OIDC Token Claims: {"sub": "${oidcClaims.sub}"}`); + console.debug('OIDC Token Issuer (Provider URL): ', oidcClaims.iss); + console.debug('OIDC Token Audience: ', oidcClaims.aud); +} + function fetchAzureOidcToken(serviceConnectionID) { const uri = tl.getVariable('System.CollectionUri'); const teamPrjID = tl.getVariable('System.TeamProjectId'); @@ -287,14 +308,19 @@ function fetchAzureOidcToken(serviceConnectionID) { if (!body.oidcToken) { throw new Error('OIDC token not found in response body.'); } + debugLogIDToken(body.oidcToken) return body.oidcToken; } function exchangeOidcTokenAndSetStepVariables(service, serviceUrl, oidcProviderName, cliPath, buildDir) { // First validate supported CLI version - if (getCliVersion(cliPath) < minSupportedOidcCliVersion) { + let cliVersion = getCliVersion(cliPath); + if (semver.lt(cliVersion, '2.75.0')) { + throw new Error('CLI version too low'); + } + if (cliVersion < minSupportedOidcCliVersion) { throw new Error( - `The CLI version ${getCliVersion(cliPath)} is not supported for OIDC token exchange. Minimum required version is ${minSupportedOidcCliVersion}.`, + `The CLI version ${cliVersion} is not supported for OIDC token exchange. Minimum required version is ${minSupportedOidcCliVersion}.`, ); } let oidcAudience = tl.getEndpointAuthorizationParameter(service, 'oidcAudience', true) || 'api://AzureADTokenExchange'; From 91dae23e025672e3c1fae8b946e2fef7d17e5e9c Mon Sep 17 00:00:00 2001 From: delarea Date: Wed, 23 Apr 2025 17:00:40 +0300 Subject: [PATCH 16/26] run format --- jfrog-tasks-utils/utils.d.ts | 10 ++++++++-- jfrog-tasks-utils/utils.js | 2 +- package.json | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/jfrog-tasks-utils/utils.d.ts b/jfrog-tasks-utils/utils.d.ts index 24505787..94aa881e 100644 --- a/jfrog-tasks-utils/utils.d.ts +++ b/jfrog-tasks-utils/utils.d.ts @@ -41,7 +41,13 @@ declare module '@jfrog/tasks-utils' { export function removeExtractorsDownloadVariables(cliPath: string, workDir: string); export function configureArtifactoryCliServer(artifactoryService: string, serverId: string, cliPath: string, buildDir: string); export function setJdkHomeForJavaTasks(); - export function fetchAzureOidcToken(serviceConnectionID: string) : string; - export function exchangeOidcTokenAndSetStepVariables(service:service,serviceUrl:string, oidcProviderName:string,cliPath:string, buildDir:string):string; + export function fetchAzureOidcToken(serviceConnectionID: string): string; + export function exchangeOidcTokenAndSetStepVariables( + service: service, + serviceUrl: string, + oidcProviderName: string, + cliPath: string, + buildDir: string, + ): string; export { taskSelectedCliVersionEnv }; } diff --git a/jfrog-tasks-utils/utils.js b/jfrog-tasks-utils/utils.js index 241e13da..9c2a0689 100644 --- a/jfrog-tasks-utils/utils.js +++ b/jfrog-tasks-utils/utils.js @@ -308,7 +308,7 @@ function fetchAzureOidcToken(serviceConnectionID) { if (!body.oidcToken) { throw new Error('OIDC token not found in response body.'); } - debugLogIDToken(body.oidcToken) + debugLogIDToken(body.oidcToken); return body.oidcToken; } diff --git a/package.json b/package.json index 1091e58e..dcdf7ac2 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,6 @@ "lint": "npx eslint . --ext .ts,.tsx,.js" }, "dependencies": { - "sync-request": "^6.1.0" + "semver": "^7.7.1" } } From 5f391fc3131bd7990ba723bd8ccdbafbf9f3db31 Mon Sep 17 00:00:00 2001 From: delarea Date: Thu, 24 Apr 2025 11:04:23 +0300 Subject: [PATCH 17/26] Update README.md --- README.md | 52 +++++++++++++++++++++++++++++------- images/oidc-integration.png | Bin 52369 -> 49024 bytes 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1dc9be6b..ea151962 100644 --- a/README.md +++ b/README.md @@ -294,13 +294,13 @@ Login to your JFrog instance as an Administrator, then as [described in the docu Now fill out the integration with the parameters of your Azure DevOps instance. -| Property name | Description | -| ------------- |---------------------------------------------------------------------------| +| Property name | Description | +| ------------- |---------------------------------------------------------------------------------------| | Provider Name | A name for your provider, this name is used in the Azure DevOps tasks in the pipelines. | -| Provider Type | `Azure` | -| Description | A description of what this provider is for. | -| Provider URL | `https://vstoken.dev.azure.com/{ORG_GUID}` (see how to get the {ORG_GUID} below). | -| Audience | Must be set to `api://AzureADTokenExchange`. | +| Provider Type | `Azure` | +| Description | A description of what this provider is for. | +| Provider URL | `https://vstoken.dev.azure.com/{ORG_GUID}` (see how to get the {ORG_GUID} below). | +| Audience | example: `api://AzureADTokenExchange` | | Token Issuer | If the issuer is different from the provider, for Azure DevOps this can be left blank. | As an example the final integration configuration will look like: @@ -318,6 +318,11 @@ OIDC Token Claims: {"sub": "sc://// **Security Tip**: It's safe to log OpenID Connect claims like `sub`, `aud`, or `iss` in debug output for troubleshooting purposes. +> However, never print the full ID token or access token, even in debug logs. + +
@@ -346,14 +351,12 @@ The `ID Token` from the Azure DevOps token provider looks like this: "iat": 1708639868 } ``` + Relative to most other `ID Token` providers, our options are fairly sparse, the only sensible option is using the subject (`"sub"`) field. The claim mapping does support wildcards with the `*` operator. A sample JSON Claim mapping which maps a specified ServiceConnection in a specified Project in your Organization would look like this: -```json -{ "sub": "sc://MyOrg/MyProject/MyServiceConnection" } -``` ![oidc-json-mapping.png](images/oidc-json-mapping.png) To allow all projects in your Organization with a ServiceConnection with a specified name, you could replace MyProject with `*`. @@ -381,12 +384,43 @@ This requires you to fill in the following inputs: | Service connection name | The name of the Service Connection, must match the values put into the `JSON Claims mapping` | | Description (optional) | A short of the purpose of this ServiceConnection | + +> **Tip**: When using JFrog CLI version `2.75.0` or later, the extension automatically exports the authenticated user and access token +> as step outputs named `oidc_user` and `oidc_token`. These outputs can be used in later steps (e.g., for Docker login, Helm registry, or custom scripts). +> +> Example usage in a later step: +> + ```yaml +steps: +- task: JfrogCliV2@1 + name: jfStep + inputs: + jfrogPlatformConnection: 'azure-oidc' + command: 'jf rt ping' + +- task: PowerShell@2 + inputs: + targetType: 'inline' + script: | + echo "OIDC Username (from output): $(jfStep.oidc_user)" + echo "OIDC Token (from env): $env:oidc_token" + displayName: 'Use OIDC Output Variables' +> ``` + + A sample configuration would look like this: ![oidc-service-connection.png](images/oidc-service-connection.png) Now this Service Connection can be used for any of JFrog tasks as normal, authenticating with a temporary access token each time the pipeline runs. +> **Note**: OpenID Connect authentication requires JFrog CLI version `2.75.0` or higher. +> If your pipeline uses an earlier version (e.g., by overriding the CLI version via environment variable or custom installation), +> the authentication may fail or not support the full feature set (such as step outputs). + + +See [JFrog CLI - OIDC Token Exchange (`jf eot`)](https://jfrog.com/help/r/jfrog-cli/jfrog-cli-eot) for more information on how the CLI handles OpenID Connect tokens behind the scenes. +
diff --git a/images/oidc-integration.png b/images/oidc-integration.png index 183ebe15eb26a08f57b8c2aab0bede8167ef2042..6021184ff58e6152b76facd3f8a84e2d16e5ce92 100644 GIT binary patch literal 49024 zcmeFZXIN9+(>F>HQBXkz5fDL8s({j^SC!s7As~hxklqujD2SjmAyTE6&|4@06;N8} zEri}n=%I%b|IhQ@a=+*Oa6X;$;XGVdlFjVB)|xeI*3A57P4Zq#mf#+Lsy= zHRJlT&29uc4ieI%~kGbHmuB?TR`g*$12)JLPrsoXiSn z4*1Kjq(rWF_t*G--&EfL$I-Uh26Iwry6y-;Q|Etjwf$0WRSfmXEFvcg>Y8~MOUz=L z33<*ZNIe|L~cx&jV(6ZRifj$?T0H1$^q81K=;q*IZ2#D^KU+9OExBO zv3XxDS6cZBI$!cUb?$tb*wtnEPQ*20l>ges%5v&iLIOPt$a3~{n*PpK&TOuj(k$Jx z9}|wKTKXOhDjU?3=s8-JA>}k?u^-AL%yu7G!kM1_ICb3IqQ7JFR(VPNmS4H`7q--H zxzBgF_H(z!bj}*$-YwJj&?1)&^MM1o!Bp->oMZ%FnHm*-olQKcCaM3po|>8BRMxixe|_R>V% zOlI%JyvD@F$xmcy^GL&+Z}yUC1XoP6)>0r^n6{|*g5Rb?qL>OgnWo#iOF~T_ z`q7rn`pWHX#o$k353k;2D~yrPqRCfe_#~2byDn_+0sp7yyZ7F{wY2DZ(sNfv?cv+V z-`|VAJARL|T7A;}W%rBe7f2W9B2PlFetYt(lu}2>Ya;aZmrMhBTZb*8t@tfAEy&9@ zUBvD&*}QXWKAL&ul3%+}t6nQr%WftCCl?K5{4ux9?XBBDDSa2!vNTP(Rlh~PZL=l1 z9dbx@i9YyFOY*eBJGLuV*REuTl7zoh*!Pt%?C@@=1=pr5=y?O!o&Uv`NR zll#m;|Jm&2%`Cls6CL{ePwqi`@AeFyKY#wBO`BcsIZMU!9JR&Lu186br0CaVbm_H#hCRNth^*o zu|PUr382{hEkP$*$5{*5adY9?yySwIYvDZiyvDEnj;P-Q^TqQa3xe~aznNo@k7bGi z4WDRj8BBA{^XPGX)xDekKnRe`5v6LXS(pPzzs@~NbDef9B0oYYBAlk4=0!YBoMU`u zTmrW~XNu11H#T=taagLxl)Q{QQuSQuh1Cs*8_=G%XHjlWJ@keKx}JuMJapWmTvOWk ztnXUe2Fki)IsKVCMzr7TGZ_jHiXJ7aWJ8Je5%xXyW>xZ4Z1z-xmL9kFpX@KJ>aUIr zwhIXf`wJ^F)C=|4H4J7sARKb+6Kqq5@AYNc)!ARIRH^K-m9pV{YV^VVIsKfZm7Xa8 zt!bLs2&`B2lW*7J(6LF;i0!cgeCE>?RjyI2QSj2!RONr^9A+LeNg9wTtt+Dh&4uLR zYlAZ6DqAjx+zGK%04Y>krdo!~u(3saf@vpcXZL}vzCIlg>-LUzsk!R-%I5Pc9ZT0A zG$K`^v|q4KHQ5*&sthMhG;sf2(wldtd{@+j7xS1_gARzp>Z zPWMjx&Tsx(NXn?L9Z>ScoT0mo~8f{)wP?n=DMl26n zCtJ)Nr)*_r)0bkVOVJsL`M<7NI=wP?{VDD%2KSU)IqdsA$<@B{Zh*PRy2q}E{A>6U zea{@KFjaIqbMCv#*k=Dy#~bxGXMI&Db#&C6!3u5=Fp{!lJ}3QCz&gA9M!C6Hr$%LG8G2wVpefg=GI`)@Kl~mmHa%Lpp(3# zGtI?G*PyYlib)htz4O%ohU1kIZ{!Mz`4r%;eyDzy;oPe1!}te`x)i+`P!KD7Vcm%XDJrdq-)Xk6_wrj@EWsoD9o zv#wLZz_!GwJ`?)LVF9n-Tkun#snEl4spP)dTz!rcuN`=Nd~NOV2yKa9jkIroY14Cj z@@defKhl9ShL@Ud&*{x%>84-TLGWh1$hhM~)waWfk}Z`_AZ@$8CG`n)LrCdy#(KCj zELOw|TsBqi#p6`?W(@;&La#7l+Wr;@;Cmkf6 zCSEHW^A8kMA|b0ZsY=FRd=`=*&U->T4M^~E;ks1=x# zC~9&C;jt}pf*X?9-Q1gqYVa!&ZK~P4zd5;ews%s(JTLvlyLRy=PJ70xu030GFij6{ zf9jx{7BH0$DZx8v{z#L)H+`ewkoTkp6>@~)M5%;VzFiG34%hs6_`zKUxaGeUw%q!& zGk9tNI(62uJX9t#ab7FJASixla(ax0sXOaW4mVWfIAYoH;fk2>Vj#Q-0q^IxMC63eTZETlI?4aKORAkt`oFG;SN=RGr>mf>O!(Bbas`2$ z+-#lQoqs=HBXl)vr)T7Dq^>4zH6AQTu1Twe>W%m zC&g;(?*2xcpWn;Ni_c4t&)L<6|LL=5&-kAR@Cyj=5}x37^Ko*w^yYPPWBad8{#QSW zAU7*lyEpE3&Q2_U`n7!J?BOoO%KB%ZfByc9Pms6W-;tc${(D-43G)BB!~c};3I9KR z6Pil?p^9tSd4n8{745(T@esz477}|V`Jd~AdGFSUPO#!dQdHhKZ~16tu%L}(~2N?14>xsC!fCC;z>gQQan?3oNWaO+3RIU_kO{BvhA;)m6_!Avf8Jyfmnd=y z@5EEf5)ohe`_@1tN8^0y0)bkVg_PuyHhps@_djj_^dd{$>i4gf)V~6WhC=toPbj^_chp7raex&jz;4cm0t84?4Q99e{C z_F;xn@hR7~0gFh$zOF;1g_#`BWce4n`W4==PTKNU;WX;b`;H}ahPm%(^Y6np(3Yfs z*URSx%L_8?5=pj`rM>YjOOB z>_h1ey*$yQ9*HS-WD^JHuaxHc2@DnAHRT<)pVS>Hm@*inpozFY_|xEh)hw?WQCv?t zPt_dX_>-QFw0q7<_E|DlxI7fE7WURSB5>O6pW=x%W_H3J=e$-cSKu0{|Iq5ipW;Zb zc|p@&sTloPs84G@WI8|G-7Mai2{)2>)Jp?B*10H&Y2K30rO9t}FT zi+%|^*A~h5uE?xjso|C8$qM8KQDmjN`~8PQ|mutBlvL7_OYh^aBMUrmhSe z*KL9as?rxe;OniM%b??R@ye8fYR(v_GlE1FWt*+x#uzXmK76#(&R-)N|~MkHhQs+>w|fe00+& z-D8v9IC_;Yb=?uek*dRB-f9&~9;k_NB$q+2Nc5EbQ@$@+EH}+*BxxK>20NI5ZMX0f ziy=v`__hi>6+q1Qz^TjSqI}cb=)y``*STap3dFWvSjQcTsQ3N5-)Sj~7gV`NQ$wYs zy}5M?-^H)#vR86}U#wlqE<&f0aDnowHB`6cJ_J|&EXJl$e!#7dJHXl;x6g4{jdAOl zh_K@RqXl)a^BG%E;u;@82zr+t7hULt=B;i|J6YTf-7L!6i}kDo;*3^sb6c0bZnUgi7bEP zSJ+p%!*5Mjdu@>4ioL#Th#ztkPq$xHY+7SnqYK{~D?M+*XQ&?^1=QpE1=j`X{K>L4 zitUHXmcnwHRkL3mWd(whDf4<7_B4=c#H0I(X?8$}%s4in2nihS^?0y8IP-@2>js9g zkp~9kN;&6pF?x!wb4}cE#T?xNZ0S@VnDb0dfN~(}6w<1d+*s0d{mqj7mQTsW^N8x! zA)e2UlpVIk3=P9J&O-O|+W`9hS{0|+@zQzP)7nR~6w)UZKH$}$Vg|h&`ybITf3)Ah zx-h7Y=5XC4J`5@N>vFFhh#Ff4#v5 zF38G-&cf+zE{*T=iger7^{u;q_mSq6`C68Oca+JK{@ak~ddQr$-y)PWpr-ESIN+lr z81vEIW~k7hyg&PMInM%s;3#Owq>{ItgFCgj>a#OtZ9e-!9G5)rFq(=DPDHb{hm+*> z${$!97u99tLQ%kZX3ejkzxfzj>#wUdlh=P1o)9+t542qQdi@fSb zIFb>2WO8xVKXrS{+{R?&x;|!098hLfYDy$>fE@LJ8)6L1vMW`9LIC$KT8~K8!gY5r zxsu#Fl?RF2WBl*NzXduJ#!DAu>DQN)qo~36>mM0Ep{NkA_NY5>|>XSJ^T3Pnj=}_C^G^yjUR(rfV%op_bVa!}GC)r)8V{8ubxp>Ztq-hI_nX#7+(DHI=;I9d=EOTs~?x$c3P zjiaTAFAdKCVOvsDegm~?5L(K39b1tLdA84dv#tdD`{s z>Dx_?=$rqzQCFnwN6Jjx`j{0ZU9Pi8wR9t56tT~^F}udRQ*rEp^*)5yJbdb+S zz;H2EIVHhpTB7K=m)oeg*s2`Vb+$4-sB3VovgbiN9TA!(v(STgu0c z+#apEbj?*xtk-DO1wIvBDzjkFMUc;Wl2y=hK@|1Wx@M!q4*rx%(@1 z*WDMiK~>yx@{bK>CesoHdSD?E5|ABt2lT4eR6IOj&HAMA{^P@~0q0`1mCwWHD-s)D zG{C3P#|Fh_EtesON?MQF&xS&;B@=7L^4Lo1ZD|TlfPwSDpRJXVq*WeM?n?{DKVcBG zvQ=Ef>*<=5^0nrD1tddF7W0&TVD1>Pe(-uCqTjCk3Mluq$PW&&2cbSnL0qqT&<{Rj zpm;2-@wj2#eXb1Wh_*`3)@q0Qaz$F-)srS zhClp1m5Xk?1A8+iO1#h4Q|kL*v6k*<7ry6;MvVFKlS~V-kosuethHt1Q-+P!> zIpP5_TY!ibd_5taIdsZCr6SpMz3o}V(9nW&)WkPY4A1cY1FvN9w>h;6l}akfi|0vh zgJOiP`~tW3dgIGS+KWUM847B}h4zY`r)(D>XEQM+jrg>%@iveyZ{MN{8o)dn zG*3dg2~74UM*YPHJ70;C@+7@fp0WIkQH>yyDwDl&SPEl0_~H#&7XGU-?>kg&Vy)yZ zz~dlCI+k}Gp07kMFhE4&qa4V>&7Y$Fk?f*q%K-!``u*6yVD$VWg18#oMV{TcINC2y z0@abj`U2*K{S@T;2w*Eh6mSWxG5kC`k zd+@&|{5qE)_w~W-e@XY38$lC%uyL-k|5Ak%0(C5375y*b(jO^Ia4iJ>O9~Qyq@bHv z{V)AMT_xy8oo)y5gA2q*cWP%a<%qSDBw-X;jlEjNx-{^IJc(-5c{fbr)SiINdKk(x% zCZnJrbZYlVH9@U#Tn?%pWPh}?5DPvSwTiBCLrIPB)lLV$?)15!X0i~PUwuh=XlEoQ z)pwOkV*BUqjaW_TG9curH5GDfXNqvoPw`#N7lGnW^On|E3rlc8@xf(wk1&a_Dj7=HfYu4T0Jah|Z_=o6YRN*D`q9{=rDI$V#$W>y8Rr7(v` z@afa1W0%vsXRktUeCD0MdSSti^wPC7q_FgY)}u935C zvw;Pt+R~@HE_8&Eq(6^hFh-?H1z4~B=13C)8I4zi*U$#CxDK9@!w;RjH50eSQ_D5; zLFw|eH?~?1x95rpEy!yv<_P{?27mYsNSIOD5pq={xA{$f zmhv4&Mu!*70hMHc%lejU!^OCxr8F4Mix8?csamP2eE=RLJHX2pyJ6^fLvuUkfW1#r z2NQ0%{Slz)K#sclNw!)l;(5W^w`)Vy2-$*@xe_Gao=WDl)cJ*R6A2l`=t^#ylg(F` zx2OrOn2n*rL}q`I&!b!sf_m$luNdiGnw z+XS)=XujBfh+72-z0>iN^4%+?Gxu&0!m1F52mk>H_w5!Xd$j7N0GS*^Vs@En?pN0c zu9JPj(8&l|2tiW~kdT1-<;+Mm<1_^-slns@H9C9W6WoUMkDT=9^kP-}!=}z-<5dnD zNj9n5`!p6@-iU)qzha$i72G1sdAv76VS}&`rGzKY9q~K?G43d-gF`D_35sPsA-Eda zkf>nWh#z@c&c&7k|9G82sC2hS0u`4rAWqRmGNKfDXDmk@=FfPHDz2Ga#n3hzBEg=D=nU6L4GL_C| zYiq@1-oLf}rE9G*S4k7YHJ9buN^5vH?bsSY3+cax>^-yDo^2Je?MLGfeJ+5=^IwzJo(_D^?Fri3L8&?;EyyQdd^ai=@o zeks)*OZxHE0Tu(f_3mYTCjU_w1+9PwuSCqPOIKUwLt&!MB4m$^wc`RPNI0u<-*Z>0 zjU`n^AhwuXe?1U!TU47$;a~30^@wxP)i&*DCVS+4&wYh5foCAWMEh)^GZ9^BH=rhX zY4y-!eT5f!j<09#q`joo;>!TcX%_WY8wwJ?1m2iH*Y7Z6Y3xW(;8^&?LnQmH#D2X*F{%~x25K?~R9WMvtHeE46$?Hux_U$oh_OV4 z>u9G7xXk|Sy_+v&_;Ke|%tC|?7?~*SsZ9JXIOV01Ao;3jkx;5CaTWr#B3hwi-4~Zl z$xnLu+LJRzu{Y`Yei;!00ERT$yP+e|dq(KNhcsNOTYhFUK?6bJS&p!!3m#^kV2jWx znles>+oD$OA2BFZV_NmRH(gKL4`p8=DYWm{W|CL=VLV2{?Ct%Mt2B^P?oT3uQ$s^T zU&H!0we65XO`JM?m7A;mq6A|s^Qhi>MAw?j-2c3rF z2h1L#gWiQ(PJX`1#J2BmJu0#vDwrAa`S90G6MX-#GC93MgW}Vlw@FZrtGKxpBKg~1&%p>NNlcIL8ZXt-ngihPcrPNSXbyPrqj-w1gON{N%wVTvcX z$D^m}$)WP?-<0ovx9N$jj2=&IGqIca94yq$a`%#Ui+G0?Ex-AMW(NH1YBhZW99i(K zdOmBVTmJ=d9Hc@uhfC06W^LzhPJ}3^fhDE^Wq3m(v;Dqbm(cJFB>n!NuI3T{da`%} zpxzVWSv%Oam?asSXzu%aPqPAJxBAB8d_as9q^Fa>k?Q^3q}p)>s;VrrTu3B0M(?pd zu(S8tU#FUWr4F)ZSh2rSf@tJQ@2h168|r=l`fXG}PFC$XNI@NX?$_2vN)C{u*;Ai% zw6d@A?7=j=CR|=*bsq(~e-FJ18TVi^#2`F2h75t~BCQA#u``VX#M$p6=cy*VXu)^J zp(g3Gy#dI?Fv0V!+u(Gq*S}Np@11}D-=@c@)eO3aTYO78pyt}4NOt?~>jP;AKZYgU z4EeBYQS=?l5UwBDN&DYzc6AxYo62n&IB3KSIE8Jk8%1y^19otH)v$-FPI?|N{4_4AhvTPq+`PE;L+pH{;$yl6c-VyM=`bNox zpfd(d=BiE|kItxgbv_ieO*jPHm&q*TgLGJ|9DEz()kF?t!67vNf(7P5W&vJ5{kOzB#C+=Evxi8xNY2B{=cq*|k=xCX38-vQf3v6%OsYKb2WDxM4T znB~R9bH$#adm=)TC7d&ciggDlXgFhNyZbI*u%*vb(wofU0C%ubv5u=}uG#I89^%$7u<&pgsZ2EYYwu`n zM>Ex!#V?>c)j}k^u;nTBo+j^STNSz=8zUxq>gS*P9fiFp*8bs}vGA`$*AhY)`8kOYGL6g$EYjiFdHAJ(z9{ z#XYtv2p(~3jX7!>W`47G3rwB;F< zWey*2-Qn93Zy1!)-Q0n``m-UJsL9#|E57Oz&@4>9-!G?O=> zr`M5-NhEO!$wHN;&J7c(=Topd%)s#;nG>NYGx_f#C&%?Sagl4*hX)O025`rQRvNWr zHbvtM4LGI~-t>d7ZtI!@8UZS$%y|kBojgvLdb6o+&>2;s(+2@~Zja$crgp) zwkB2m`gcL_ZbGq0GubuKT8oAFb7^a`12R$7#NyKM`+k#}w=yhLZY%kVy{@GSz1(=z z5YMSSp&^l<$ZK3aK}d$oGV`$L8aG-Ohf$gNm7Sxdy%8%2)nfT0R~&vCwE^3FG0wv; zZ7*D4xWD$;q2!&T&G*&bzXcp7N}E!={YTQDp;Nvr*OWPoV0+8SF)lou z^{1aJigm(vL|k?@J*R%4#xXTOhZjs^JtG9j*cfo|gWsvk*oE0>xX`q-36HZuc8>sk z`&S1wQd1~}dq^*spc~}`!CiV26|g!`?-y!#ZhX4f+~TQtV&K{OXesoLh?Cw_kJzUD z2|ibQ7z1(+*6Aao)|B!!+!`d;5XInQD4!>sjI9gZ3?a!a-v;%6jhm?{i(O}>d&ksY z8|17?UtkG@IImI|6(_CToQdKRU)m!zu?KTRk9;+6|kpTa~0#& zPBRB3wq{@BdFav>n|i)HYlkoi_D%X9t!S|fHmi4iDh0zDaf^P^jC5VIHNp>CCVlr; zdKGEa8AcA|a@x{wDw5d*BmZu)^XmWTMfwMwPotw(O7Ioli$%!ww+?)Gn;<{EevsSX z#zyoCl$|ouq}n#Q$b5iZSuV!$K1BS?o6b4*Ym*gdrAoBGgO_=3ANiZT>)kqt@`bYKbamh$;o*xYSM{ zJ=f7|rLjuT3j-kq#=jgMnGpiA?~JlZiL^Y1FT92Awug(aR)f)=Jf=Bako`DylQQn3 z<83a;64w=90r5`%#2%*g3d<=YA3A?dqNBatl7RGEmp~^QYNagS9dW$4C^w3Nm6CGX z%?62|p0(Rr`rL-D#ucxs1N_=TVul=skFd}g@S4k5xw16_<(*5~`DZs0J_xMFx|+7^ z>O6|LM0FJTH?}0Cv(g$j@?2xEE;B*MqnyZjoP`5x&8C?lFU+-d1EPKxn5Fg_v zqj;!}k8zwKmaJPX-#xuVQ-a)YqDmF7cTpMvcx2FWeU^OrlHQ-Qeo-~Tg8Ry1Fd%8A z{Dr3Ez!aa?Z4Fybc_t)#xEMZ;5;K=>aEv!_GtRpjn}anpmgb%b(rx)5(gZAgd?6NP zIUy@wG!4LQF3C-O&v*J9?n8O!=!2RG;|SFz_b3HFg&57d*IAL~hsS;Q&(|SDMgWY^ zgRnNE712VPt}r?eF0)!&nA=0&uklh zVl9)tO_xEBthEdguXa3A838*3%I%To(w$yZMS5lOhIyqR2rIg0p4x{LaWJ2 zn(ac6Ss@vWkE7$v>%zjx+N-*!Umk%Pb*!88jAI=u#f$2sjwU)GzHUQFtHC`%%>J*E zXQG+s)t`6V{>K^wnXwR@oRG%noN4L3nCH0Py(IzE8AP&x#R9`ZM|F%V2r3kU0gIZ? zK))Cg8)m|0O@n?wQ=4SQHWjnWlCB}MrhwzME)}p(o8*zaX1{3k>~_L#Yc5-l0DLl> zH&;7RHN=|`$C|0#+O*XMm4yh;5%9?2)SHNEIdzi0&B5F2`R5Iere<`_pRqORPRJGR z6Zd7q-v(0Eoi{~%#@!`$PaV$muxSnFD&-^lin~X_vI}f0thS2Vt>@ z{y8DZsaU}6mnMXd>!KQ8F+-2D*K|gEX&&+#)s9|nI(Y9Po>`n<$b3N<#Fxr71F`;u zv^AJlGkGUmJyjf&gZi=ob+3`H^JbRykS>?HE&LiLe*FUOj3EHYRte&N#{Lr*5lTyS zzuFM}Pc7&LlSGiq|1T`|2ZV%`2T(fxS0o*zM)4s{5_1`fi{g4$p#LqR7+v~%xE=~N5vg)JzVECQ*#>f@ zEc*Dz{lqYmi8w2l28D!=4X(Hq$=3-Ol)rW{t@W;pcZH&)s}ifkDz&Tc84%M|ZFDCj z?7sX~LUlZtEL3FmqFUndi~D`cF1kf7A>sy2j!Ak4&NGCteI5O2xX^*4(6HXOz{BWI z0%cw=h~VIh&S4?oh1Dw0g|M?CllX`X0H(^JCIG*W!gYR8_B;dGn4XCX%a<^HAV;FU zTCqW4uM^X}l3UyENZ*BZ^@=2vn1Le`ib_3;lap~XHT*q zits%)#_WW#){!Y^(`u*P{Rlc9dwp*G(%T5H>Knzd7k~p zg6?Ifjl8F^e=1O|?Wp(nqmko*RBw;@g)}kHZ?xQdC>X9PC~Y)u%4Vz+H4(ciT}DmV z%r8rt33Z9D7vX+XQ$AHlBJMnsD&G|3k37_P6NhKTVz|&&TA1b}G=w&a=ksKaAi&w- zyC4Gvb2QC=a^S z_XbF(>wm!Prohf`I+-u5<1o172*sTVDCbzJlwUDi!kB{@T2yRaKiQ^niox&hute4! z`!hGcCQs!1NnydQ|2UDUI~S9qYQdceMEJ*FKd}x?as6KQdv)_cOHx+|0msF-5C=4I z4(!ecjGUlgQLyUK0L_Ni5&+-c(XPQmrktpeBbBrC+ z467Mhnchzm1Grzenz0;IQ0n1Rk)sTQ#dd&?wvA8+?5#-lKat7?pO*Ha#}hv`T2UC z2g`{9b$o=0nPXAB$Dtq~;tf7CTbfhHt4UnAFbNS&!*vVRVY0~ovEwlB-ef}=06L;8 z;<9>;S@Al4-E<@z`b|@`>1fgh9@*;3xP=S{N7ok~ZXIEGNE z{4?RP=?r?+Rgn=n@m(C;11SADdGzMX8b6|I!;MQ~67V`&0ufRoYB#QSpfvB`xBRhi zJ)W2uEi{7MBUFl4z1_EeRCOB%#At6!WW;kd50VM!JgM=-T%KA~qxi&K%lscVweu@zB~ZltB6x22vf;@Db1FU#F=*SnMp4Kk^1@HgaR3J0K|2%8c|J$YsVj;Oi#MNa2ho z51=4a#yX&l{890mkybbXzr}cw?fKx^30Q44Qj>})3x2Z(2+cU}@m;x2HJ%0+O=?qE z5zP8_k}3{9cJxxWqbo=oBR|R26F|SZZv-UnO3K~aqDxX>7^-5zM?%>os=P+t5$kpQ zFt4(11nNxy_Vh#$%@*bLcO~(sFzN0*7Wt&FHGsrgP2^!;M?CMww-peN!3m4qLO~T@ zOrG*n|qVh7JUMKKQOw{reO(;yW$Mhqb_3CyDB&6zr{h~g#j1W# zx&yG+;~lNOb4jXttCX`55{ZRFs|n1M2=2$PGD7w8j9kU35>b#D-;)uL*XrA-1<3}V z+x4@-P5278$?w_N&Lf$*Z-Y_%J!b=SJL`On^~@kb^{o}7h@&UqDkCD$Iy_|tPESwY z(BM0@9{k9Ro#*f|bYUZUqjU4c5$xsa)v~q#^Qk$KY%=WIL??GU$x$uQ%W7#g3{Q$D zugF9(Y|2o1bRoEMmq2r>M~u$LjzjyboWQduvtjvh^BiB}?)=GR@I`NxC zULooyy-oUVYfHhx;FI@slRMzT;NT`_z}E3+#$19o_kZhW^6TZv9y&BXW8)*n3!ocA zZ?t@QrY*{}=;SFACaS6!mu5KWAxds|?2!p*m%siekGE44=*z7KH$vOP4ZOvwwh6AOT;7Y-rs2Q z=G@H|MG9ET^))ZT;Nl}Tp9euYNsjiuY?aFBB?Wwm6Kih{0N7Jf>!p=&z}WozQiRM$_>9`Fs!qmzXfdM+OGd z6O<%iARAwyo%U_xhV!DJen)6NMAHft@!DNAZ+Vy($AQD8xi zYXMHRx)K*3hV{QGWLgIYB_fg}2N#MOI+vGU(YfbGmPV|=R|NSR=YVjNx?pCRp>(Gm zr#FD;V~(i2q*$Ssh)-)M<~W8S?vwh^NHdX_Nd+2M)_jR*3eH;x50BSl+L*INe!P6s zUgl!t*HI8g2TB^m$O9-sK7aWlq$S}EN4}_Qe(GQTZfoQ_v%|WsVIsrXZ!*hO*3o_p zNUhHK_*VK@1>W754X`y-tgR$xQ>y_OVS27anoi5fjn3j%;$FRxnJE#&Eq){Z6Wp|8 zR9RVW(LV7^m#6@|9IW=o5%H$;4R(YM7Nz>%>!yQGok(Hd>i)i^oCIOYmgZ0312P>K z{pw*Gxh~L6lZUFNSeV`Dh&(=e&zcF=P5Z=s{9)jFcAT7rgBKg;VVABH$Xuu`@8jAc zQ(T)<^{7kidFi80!{hgnd&Y2>1L7m+w-Rhues>!ObN8D(-HLrLq z={g66r}_->>n2LaTL7dCyu2`{61|y^N7JL5-bhgzz?{nSM?w&MZ-EjF!g);gP39X6 zcm%E4T)!U^rEoJLc}b`_timYXqD(k-6O&kubhc#K{+vzBO(HC)uOZ%q$RMnabPgQZ2F>65l$b}eVy>H!_*GlS3gO|>N>p`gB?2+ z0J?uA?o=3i6xPC=XOs-DkV($O(vw+9$2X2F5z4E0V!y%rSFxC3P=O9CLrb*5{YQ~e zU*-(#Wi>NGI#169V8JkSzI4a1-XPqhxKx%PcwO}Q>+8AOislS{h0`T*jGM4=58l(A z^z9milij&KLEx%Zblz8qFS*tQA|BDXrbRO>W}u4FZ3}j>PCbEfN^==PeHsP{^HZJ` zj+#BC+az+>!yrgH?FEi}BM5&^5zudW>%)?JhMESO)<5b-MRRSfnBGj4f zusH7-9If<3_kG*7Fgie%@QH=07oE13Pes8pWf+#Pp#B}=!DS_k!r(r<>O@YB>DB2A@T&e%G4M|G8b-%sEO&6XX*YmyCw$GQ zR0_`;D2t^Q+l@3djLkERF$)JeZ(e=S2NmUL?bAggw>-WQjaE&GctQhU;ChL6LQ~5 zCg<+j;E!xkkDx*4XZf0lwntq1&n!FkUUujB9T_`0#$m770z)#3zOd(Ly~#_uAq?1l z2jsZS&%6cPA2SqXIEyK5yS}XY*4pKGHC&r~f}MxJcF(O|I%s#pUIAqcd);?+Qylk^E5Gvu5Z#z6t%c?Z7neIQ|-ex~6ss6pU>x|E!*EGEjwxK8Y zo}E)C@Xll>OLmxbt_hN08~QWq%lVP}pUz+192___Jgd%tD{o#u>etlCno=1Q1A-#U z%a?OtZN}a18@ZkUT~Q5n_N=u`xFI)#ZqetIk*7%F|9B>OS;1Fp2kCnlW6=$LUk|D8 z(JR+($nG*WNX+w0ZHQl~3?30UNmSFbCKIf~(>iIDuhlKu==GoCvH^y&0d~EW<#K&t zdb$&L+-W^-e$W##jb)GU_GqR)nPOx9t%QHi6fPOfP;ks4cGw}wgpf?jwj==+nW+seaeb!RyLuut*wsB_(- zq*v^Qs^4U{My`Wwr*+i2zyXXyPCGq6ZMwJnq5AIq$$kF3+owZ{k_-n~FyrH!o}gj` z)6gV-A`zn_RaJ~KRF9V4Te}I-@3zk#Bd;jutjKd1W~aNv+$X{%M&S&^AZ@x*ZH_Zu zZJ@?-nV1=5zNU?4? zQq%0t14buBd}I@esG`QkxFNqUn&Sg@y^aBPQKTyTVdMS$B5Ne^2HJ!0GQ)9e6S~RD z@t2zp%I!70W3pR&aK_?Poyz2AWpS|9HH)b5ch#B=giMbyPdfcJyN3RBa zJ=0{7^76ska?i+Tg~9>mYfBHyX9YC?thD}IV(<0li>Dq9s#m|X@@FfCr7o-n`|NK- zA2}^}nL)K}X+a%)$Q4T&zjW*Np{gRIGBG4FL&cKn#-hh##|lYBqM&>1>1Eoh_@Xf# zVR{(is)MWOnUjNoO?t2b$8Fk|r=3ub;0o5je#^Y#KgrjXS?^L6+U%I>|Mgn{{o7}P zu?7ZCh8R|1(?3b(9eAMAUf$aCt&l~ZgO|E8BIyt#b{G0@w>$k;ayABi$)E(ViLm1Hn1ih4j5nGZbE^-T zS3HmJU5~8WxI0Gp9^|k8i@moDs$*-rMH5^D3GNVr2MO*H+zA$3g1ftWaDuzLyDgjm z!QI_u;qKgK@Avz@y-%I{<5u1C?@+5&QN7mcp7WWryXP~WF-8*sgq^!hZoAn3DLDb@ zl`w>qO}cOt^WO*jPrc_(5GX}?r5Z(i_$Sm`Ee322B{qTi=f?9Opsx1JK8jEF4~QF1 z{}-?oQ(yw=pBuMO-g;6{ce$)ITO`nGR*kcoFA!$Ig#N{Ev<=};lDAPVvo)d7sy!8$ zCo6vs8;}(K3S1;%{wW7TDx?elg0MF4yX%j-}CsmM`l5_*%2@NhPVAJ?cHE zQ#bF7MxLqF%`->IZ4}uGyBN`W-NQIk^~F6v?GJfQy)%>gW+sfq58N<-WWYA4gBnY$ z=!U)3_=;W>f- zi=-9B@2EipBnvGKdtF#>1AATv?HvYtV#Xq@ojONs%JQog!8V-V(cKVDXghgwG~%BM z9)1~AK%4+?U0!)FX9mT4ge@y{2K#gJBrK&^pPbwJkEI_T;PFCpo-!_;e@}#@5 z-)jzqv~Oo1N2A4FxP0j(maEn5#!|h_)?uKBTl9^OmjLmXFXI43{DR&*N&2sT>&F4D zRTiI+5%Pf!jh{bk#}aYpDQJrV@QG#j)tY+8r(XM$je|O{#qNmaetCu_hQe`Q?S9Qs z)$Zz0`S3U$1e`wqT9%PkUBU`(st?QGh89tiuRU16(e<(owwq?)Ot)#usK7QYHj z?gVvCR$9NIF!MNMvqnQ>AQ%YXF;~g1B_*s>rE5mkuCIpG^1UQmDbakdd|mr}sJEy= z;k{c>u2|MNQfH}&aV4+i~-g9C# z>|zGQVl@N{xouYm3;h6Uy*bs%MhjHwizOeb@TD z%EntcLz|)o+wg>Q?91yoaWYdSjp(-9yUEP%3mi6cA{z=0!^<@?{s9MzJtT(|RY^u@O=0Qh5JL zAY<-?>6sDQ&@~c&wJc^;>yuL%)8pbVR+9s%#Y&SJ3;@9DGj^0JsGlj=9e?H_E&-q% z_2C1h$A`T=(nXbQ@WP=W09rms@>Ick{Y)ZuMjz1M}(?jlA5xB0BLXFZ|>b#n*BKIGc|3-ami`Y%xV zm*oIYy|Dt`Muk({e$9tg`+4eDtk@j1I4Y{C<5>EzF?}(YORuqDNRJgp6_w89^o!3B zdQVt0Dt^K9k=HKbWdaj_lZff1`a6vKA;i7j(nCek6Qf}@&+Z{c$Bf+x-_b1Pjg|(; z(@%42WzcoC^aSY+P>IlytU46Fliv0}S7c$my z*zy1J;!&l}#M?jy&sOgr=eyPj;;Lx;n$tf5KSXJnZGC{~9KO)Ucz2H0d|~j#x!^iT zy@8J4arqw2&Auv}E;RE{0FX$(*0Y{NPalOPpOm?r%(t`m+by1YrJwK0H9-~|u{imx zALEWioi67gJc_2VZU7Di$in<=I*#mHuYST{C8am$AbV0%EAeFc8yh^9--LoX-K$z~EfN1DQ6g<1xq$Cj z_{3^yYP@=>GS3JN%lF7QlPbJ+JB^LlUPsWP5M{hvMdRp1iCi z`%HBpjH*#lCy#Xk08Sc8`lgpT6a$L@czLGw8xPT&7ap&w3Uaq6SJA)6rg3)aX$NgiuLP_$GBU;;#X62_T6`5Nklp`dR*M*9gK&E2<#&pUPPrOtnJLg!E}k3KnFizOLu9U#bZVi>idtY*(QPy)6fV9 z(X88%d}S?Q*MhKMh_d~f=j*H2LcnpK{beLe_d=uiq(vN_Qx2WB1a}cAlWsu3#bFI~ zRx`JCloD!i;-aDP;k;rBazL?&X4QE1NXP&n>OD)B(HUMW^=L2mD;6tKpZKL= z(9GUuj?*vQ5P7_n6%!k97B*Ax=~h4Surz9>bEIwuh%viqp4ncdLqjBV*6{SM8ka$3yfg6cG1CJ>s+(Bh zz7JaHg|q+*NlZA289KnVaMcrXskatNKV&SvcOeus9OF1~bc~Y3>K<$IpWp5bOt*ouQUZ7&E zaOmPJi}Wa{@ld)7&|uAF>JT9wtIH~wfa^{_#sHlDnS5V~JhQmv;9#mf$e#G&=-&N8 zY3NVuWR=qd%b8GvzPk(0$G>xDSv>dJWtU6_@{z6eN_g!yJ&xP2Y>BX8`m(Q>SwGhi zQ?p|UERH`Pj0E=z)H%&Joqq7dr&?C3SQTFe7FjE&KDGIR<$Kk_M`~nsSsho$qAy@3 zIRw`drJ^mrgVXED3wDEKja~Lfo?qj7(xa?Je*B&oV}K!3UfguXUN2|y-i2c=2*-A1 zzf~~f0``K5yFDE-0#M1?ws~7Jnxr=PQp6>*P(Ng$a+r+5XFqS(WWCvD!NNA_^6#fZ zbC79AdnBYv9BV&4zlzK$dl)Bh$Ks%!O?W7VBsPF27lqT-YBO&czH{?IY4P12;Dr`Yu4Szo`E{hWFc;ho zazJR*$v2>^EZJnVCtYSwJ7t`dCj8cDou&VxSEklV*AhZ>qnM>JKgQ@#1KuIe-J7VY zTfVq`F%MgeZ`LqPRdXIsEDFPvwtDX=1C$MR$@k}U4t^AtJMGh+Ph<{UjP6;mlqkV_ zbWYp@B!R6yjUrHfh;QjO9VE7v{ITe*nX5)$c##6D%rb>v_AYJ%AoTPp#kzHwf?|6w zjrdxW>Bnsc|HAUP(R85Yoy%D7cl3WH4D-K38~bhCHW;@^|H2-0w901^gkP_BXW;bX z$B(7C1Z7t1Q>->gQME~vlEGARVYzSl5}RsWursaq5#ZikU%yyQK}GG&s@Q#bLm>;K zCs(1VRX%y^Y{Unw)#nW+K~qt^7G_AzTw8w#;sgQ(?*bcz9#M8<9?d0I_(S0x!rpK=j68gWfJX$xCY(> zCbHxuel#>8nq813d9wUt8-><+&9KSmNb)x0Ek>Fm4C&btkETHfHX5zZBeE;j=kR@v zRb1kF1+_A@tSmkOz8|4c*O@SsZB?UFDtJd>8gU?CJ(!omX&3hkuxItL*M(KdhPexH zc9@?_Wh>}r9;0$gSLo?NbIO?qM2;MNR3zE*oNn1GPaWTFRgu?XpRUXC*=?A#f?PKj z%Ue56Mjf2E*FnOjpxq|B@1#Aq#ivJ9drAo+1VJIyE>{PN4Q`grQ_?Z3OOZLCjh&#U zCi4?R-ot%z4>)?N8$mQhe}D!*{4Ss9acMu5IoSW2tu9RO)|Ff2jSnQ69M+1?%;YJi z{pNmJXZNFY4iIR@G{bGkcT|3uKCr}@Zd_pt6| zi6|M9tBlqZ;;pm@YC2#c=6P$DjGZkfm4!6CP;eD@HMi%PB2go1;(BB(td|o@Htw7$ zMwVj{*pM?6+IvYEgQa!sehbYtK0H^j-_4@xpXyugzkYS8*8gFi2^9LAF!39Y3f2Pb zRPbTRGr=~-+dq;Aah0A&8S^9luw@?Q>nvkkQAh2Kjp!YnfLeZ7cC&>@vd@{3I99PL|MLQ;Tt^saaJrgKi@(}Uj?4x!1zXVKSOzJy=d%P}T+;Oz<2lXrQ3 zqznhi*IZ2nV!KSTag%GWRWAHmim==I0h?Vd}D+951$d;HBiPobc6J+?9;m~t)JJ1dUu zxwP;~Jy&{e*Bchk{POl)dfQF~Jw8ur(xeVJ>6-u1D-t6D8F=-ZGyW9gncPmF@&VWP zQ0R#}aUV`Rt=ZfW&Rc9X@L~T8pa4X3i5uJv83NZt|3s4B6$1t(0^5dq{{kmotubsL zaP(jPA%o>#%LM!%2ox<@1OEe9{q>WkS4G?ZhuwZm?QDG?|93BljS%pMMvwfO%2JDl zwO%2BCQ)K8-WvF9d5#wYiJo}?T#|PQ5dP~x97_Bdi}#Ns$6YKRK>;SOz4)W%bJ)lW zh*4}Kik0Xr5aZ1&m5zN=34WPTr|7?b?Rm#rggra8jM@98nO!GGtn&Bsv{DbicK#VS z{oSi9Kt@w-$abMjquy{-okzpE5GcKPG2>&y{Q4C_bU8<{PU*Ak0F;4on{al@A#)H3;Akulvo8`On$@v|Xe@2aX5*Y6!^4x!Z6ZMZQu<>r++^+Pm zuKnjN$^^iVq|he*8D6+83Si@-eLaWrKMn;n0)TY#;Z6S61^^Z`oQwE0|2619MB((+ zfB~BHXMX+vzo+5dtI-NynneW0KikDf3qW8dUvdAtORsCQM}U4BmodWH_b*&52@}B3 zm`VO^p5pmxo+4|Mq9^>1cKJvFoNR;SD473=6i_$fd*#m-)C~X2TZca%n0JiQV*hq; z$$0fG`M+WP|2eFuRtSg7pjqWoH9fl>x>^D*CxeG_^nq*IN}tadiD$bSq2aXV$Okh+ ziXeb~Q!gy3tO8OVW}JRU^ABqBsTI8WO0*6nEJ{t$HmxFM?<;TVl}qSJL1+|59Uoe$d`<6Zv4#pzk#c$L z`;_)q=6a=5ECy#Rl*=S~#yGp%a7;)=WGj81i0ZlmT=4vL{!+H)Dy-ck*_m%y#T=er z$Xu{BOf)SBl*Ff}7!aX6jR4&KS|-^em$B!;~K7_7AYau}nyH3&Eh2BfeBq=B8Ye*LJJP&T5(I1*ivl3eUHbmW_|*i%n(? zWhza*ZA2V1tX385?Y4hPW=d}+>XX~wHkyazt5G7u7DGQRx1_h zL(dHcRr*+I4|BEp{4Gz5A|Pg*v|K-_ssri?pGVqCAUyFFZY1IR_h{o9E$+`%KxR*)s*&dTU+K@d$+n z>%ldcu9kj@weB&X&k|91C#O%k3b3L)eG-pzc|||DiuGvP(_Y!6te3F%HDAWB(# zs>%7bvYbeBz5Bn+Va`LndB01d)9+Nv1^`vA?CYArgI6Hr#IUSGw|(PS>A-Wl>3AVC z(_}n)`?|*|=di*h^l%^6a;d^qnU=la0@aIV`e1vQX$99N8@A z86~x$KHbeiJj`ic*vFilU&vmh$P-xJ)^HB)K4>6)rz znJvj<8U2Tu;UoV|&PAZ4Fi(0cvv?7?vU6|HyQqHRb=*8bHU|_ct;}Z1Zv2)98jqc+ z5q>=1^aizQoe+x77f+jMdMkFd*Sj78b}a>~=KJSLo?I3vvIsl1?z6|sZ4u8oyMlop zyMEQ>bhq*;8SZC(gNkw0mUP4=nmHjo=%4o>YxOwm>HyW#g9Dr8%7$NFX4V(9{P|Z( z^()gl#+A^by=j-T+?VcZz6ikCjZO%)U;43D>(!=97T}k;7ArRM7Y41o^oKQ3zmF{Q z{6)FF6UeLvPqhAr&{^iBeeGqJ0RrrHYi=o3^YX*Ns>^EAJmUbTbJ=JQ{RO8yMWb2V z0mwEIc|$Q`)2x@i%@i16DLBOf)zUi;fK=FNZ%JgYLqV*PdVL zoZtykCrt}&4?fQMVMb{B{}4G5n!#OF$H|!~Zd{I*@08h=>z+<)tR7j2NpwLhmU4Y` zyt`XtSdn6Ew_lO*J0O=Uk$QIz$TvzkF5Gwa-z5LQ02Ub(5ck{c(1gIsF=XJuOep^LyXj`M zeZx5bl7=ie$Sori+3V%n`y6dTWL{J>^?5!Tw4h|8iy`0dNtS3-wK(uK>s9VQJ$pV+ zkMe@AmPi|JGr_TF5p|MFcye!(dnp) z{`0t*>r=yHHTmvk=S7{HMt*UD85>cjQ^-7r;cvYn9xv0hrv=|O%T9uq-6J8cgvKro z%0-35ow`474_8-sVq0W*T*bJxMx*q4+RRcdFHH{DWFp;KCxSe~E;bPdKzKd}24}w! zt>zVOR@WdafKl?jVtV+_Mlfr&q#wj$mO7uW0xUkyE4`zU?k!7BRs@>X&vSKY?w?Ej z1y9p7D`rbHmzPuTLW!w6?%AF#SKGR+l;4I9Y#7kcmW!2+^4>uo^WiquPZ-3-zLnoO zh*{^GQ)=J=IC-ra3H;CsA(;u~D%&8hTulBV+Hg0C(STgjZ3JHL3C;t|EUq+!l?nA) z`etizM9#IUaNk&?fJF+sgJJd1_g9s~Fg3g4H#U)1Yx^i|DD+ZFyVXoBY0#tZMKpIQ|=>(swlu;&;9Ub)qiVNOa;jKRXkko z{YY58lq*c{9VliCaOEuoXN9-NFX1n@Z$`Yrl>K|aH+oglmvgCW9 z>2SGI_6%95Rm&S$%;fo|q6udU2O_lfQ>HSZD}C*QC@_7@EMs!vp*AIGn&q44A7`roPHp`90r{rO8SsX1)J(mU;jy%rrD-ucZ|doo%)3E@TibleEm)Xn^&F?6YW z&EwFjsj5Iicg^G`76+4l1u1WS{6iD7(8#pk)xxg<2yBFOH6GKerG0;Z#GUzz4Dfa>o3p+ z8%SW<908gn=rqKX(JLNuNTM*?pCRmykM|lhZVX?qmcR)j$c}ywt(M&1=v$t%r0&7m z$iE^H2CMqcVxYvlp;Dn3jVYO{l}@G)=ba5z1&ZxtC%-cgAp|@6Qq4lb`>C3Kph66R z?II_Cx~mY+^d2JoDSdJ-=avvucvW^Kz422(+r5AUH$^%yzkkv&$(mDTx{dIuWPk0n zE#e6_=f|4G`On@fQ-m&xC>f8l^Ez^6g5A)vjxKgNK}k${ZBod<2u1{1KTajh9%3mJ zG>7k|pZ5-~QZ&J7h>6BQD)#v8`aNoQmtZ0(?lutl33uS&Cw>Uv^^C?3K{%vmOHJ1n zL0A6eks*r2ePrNXdT}V5fSI{iz57!`hue$Jn3*$ePVw@pXV;$u&CynICI~eFYy$Eh z>H>i(aIy7VR%WIC{D4T4ifo^QOU z*?t1o9L~;TB+OS zHc9@e*JnB+AtX2h%cWw{XeRqMSKR<9qZWGu(Kr~=l^fdB)_4#A#Ju*wkGVoa)y@oNj+4VHe+^FW* zE-?oTQWWHh$9$YUyomItb87@f48wuMm8Ou_;e0RjX4AxW3n+lzpyf_%cDF>#uMct*WmQz=oh}t3)0Di|&2|jgniLVb*j) zyC!TL@g%VNJdgSdoB+{<1K$O=D4%~q1?j>YgHE#m>qLix<%5@F$sGnE(Y2nAQ<%;u zI05C78wWc2d#Fne=UEJxPi;_73;Jb~&MXXFf`Oi}{XdUeYYb}r#ee=*sdCM6=gN&N zVfUx_NS*DmXh@#Mb*);dA7=*Ap9o=M|!5=funD0R7n~14-q_{D@3$1t;$|Zm@mGC> zW)_fsKkTci_)@3WcCkC9U*2%A^tfz_CZ)_FS-?*7cg{-`)2AN^G`MD^F~N*&jux z^tI>%80ar>xr*|KXXt4P>J5OXbM5w|Qe!CD8u;}s+GQ@N?XTDD z%XQ!9KFbyxAB$&LNU!@Vo{4b&1Aj!w1|aW{)luNRca@<-zW%*ub~t=FVT5tWywGhV zlK>NAL@F&znb(g5NKqw7@pgq=jLGf0PWiw6=RhcLxf?b~q42U+ekyurh5teb-hI}Q z7Wanw82KiB+*x@uDcs13AwVJ)EBO$+)qDM~o{42bZGfAk1=S&1->T65H5a}Tql*Be zr=?@Z@}IallcH)Pq%>UE@%**H`vvOj*--w6Z9cDK@xR*o*LC~vaDF8VVSD?pcmuKj z?F)olrDLP~e+l^~ezK68e+3 z+Fc|8tf_UPQ46_9qs@M7)ZuJ{Ogt{6;Vu9XYkO$k?rp^?>FM zxs}PR&sc}FE=2W5%vqM<3OCJXSbYk7j)7`c{pzFhg{Tj?a-2{t)+mGB-@KO95#2wac z#Pu-;AE|fv+9d*v)>_|c-_==BI;k}|<~*_=M;aG27A%*Y%LTEH&p=-c>Rx?4TB?!d zbTFowrj85E?|=q#Prjtl8%ScrwAV378TLaa@g&pwmgo! z@%c`QeLm`iXz&{aZR-s7B>J1+O3eF=HX2CR_K&+GX$ibf?H{H(5#rkkmP7+l4#?Gi~Bmr25sI%C$iU+r^DlOIBH@$%-uYO*R{ILG2GdlF@8WYh?)048Lx;JtL#LTCMhIFkfk&jGPdx zL0r)3+=$DfO3hp0C&s>+M-H%shW`!u);0Sp+}&p9YGGbmmQ*_HpvoyC){s%x3~mv{ z8^S^q*zl-s(a1r&3J+t`vlYDMPYS(A)q>rNfgWr!I!!}qG(lB?N|fIx4*lNkHxw}$ zoK>^f9{v^=Phc(kBuQ>7>8EDvRzmJ;x8i0bdAE5o&*=8dxNj|rXfj=!{>Z#8n*_3M z+Rp^+Tn&+PHTHiPE+?!$|M+?%7s=gZ_Xm%jm(FWA(F|tvrjQN7_TUnSiC7!BxqX^N zQ!devA#7^^9uqn^TbB%h|DsF$#c)Zn$$r1O<vjh?kPAcU_Z*;dzZ=}a_x5;aI?z>D5zSxwE z-WQVtBow(aQ;aw_E`us@&zB2rmxpZ%&8y!Ku{rV5R`DqVv2r44&;v4e)npnE9fOy@ z1)cgstvo-;Ra>vB2xv|eVUk*Q3yI~zmz%2zwCn(@DV*9IQLfMpx ztmjs##Pdk~p(x*SywJ9b=_+| zP&oUNYtp@7ChhC`EfGmH|rUE~bb zZdXks@(qS$Xx9N|93I!DgNxpk?9OC_vu~ZR2H1)iYbK@$48FQ+nq8Z#X4?$>;z>dO zlc65}IkMRiY2;hqm(2p)yz(4sPdGC_#=Gtcg=*e|>^@$9Ol%aC` z-2Jsl7m7Fog|iB(%0=gK%5ji*tg6ITmfPyx3|4Xt$x^c(XYf5bGfR2VUq=n%lw(`X zw_S6vrnA;M$zcO@A4XbnpIN)72nK>dQqN}b--Iqqurm};f3WS3 zsurWNv6l47JW67Md3@cn#QlQ4G}=sLlvhu(*uw2^f|2^ zrU%c@OS{^3SmZTx8}gXH^I3$xD9jvFYA%Xh(`qaoxHvtb_!EBw%GF5Pm{7$qu=bAL z1h4Qq+?VDm2EeaZD^bVBWl%g*L0@ct$x5cQ`(4MV&QfBv@HS-Prd=w22GrWvKISfLkvAtDltFv3oPs3KLHIEE(WpfMh0Rcs^LPw)j7 zt5Mh>2Pz}7pd6=CBH!dHEV>D{#u&=l{5!}It70LGrDnnW;Z%BxDbiLAub^Wvbu6t( zn8Ezi*q2Ap+4)tW_Vj7(Z~yg$Q}s*I)rdRkjQ3~;zPv%G5$dJZo|E)p_xnyPAEhUs zbMnE_ks0g;Vfvax`#R}yb88ww&E<-aYQj&*>Ya|xkV{p$ zY(9517JtFYJOr~GiFBRdQstE9849Nk4!`Te_7|ntDYsFO_m3d zzy*?WqZkcoeG-k#U>H^O|JL2ert^m~iP57TjB*3JgRr?W*JPFfUsG?8MgN=S2N#k8 zAZbt92RQETweEMrDw9s#3|mDjEBDgY_Zy2py?ft8@ufPPCgTQBu99AzE4_3&CU#I^lCxalL-fC|3MT>h;Xj#}FWZ?t3Od z6n@$Hs2LXYL9OZ7;?2921C@41jEj~Ip3VJxYa(QMNOPWL`t3RfkH?YkCb94Dv9-51 zR_sD5T>XoYtv!yf_7HS*8OGN}ujqr+h*+pHUKdY}J)c=kfyW{Jau1-gW4AIy5sUN`ttC)2| zT+nQ!JB*zd2401$TWg;2!`IE z5bVd`de*DN5hE>?IfIlz%bpvl`;+SnJq|LIwlRuTjp{szlm&7=E$6k=Z&10}OFL@b z3Zo*qySQ|`_tS@Klzq8z6(jl}t+FF$c$(SATlLtRM@e=!#_ zdkzlp^4#rqXGUW7oV|BwYz=UY50O0k2pwMiIC>b6Kb-ky_?uM@#^>2W`IRNSM94TE zb;IwlMmJR%9Mwi&25O%oWbMTkosNHTAjYToNMDdUXr}iTa5;@#U`4&OURCLw`gVG= z`JBV`V22PN8#sp+D^r`n*j-~g&q-j>e>_@bW2j|5uO*?N*e+s*Z@03g$8j-NcT92~ zhFb5*wqch^NQ>{!UI=f-5nN8+h`4lKQ%yd{)Zo@HmWY1epMRoa${b0jrC~K`kM4Qg z8A>pF$&z7s&ho0<&PS5LOM1Qq^$Z zJsIjE%iw?Id4xm2U=-cJi~Si}2!uGoldgEdJbchjl-dFw(Ry+YBRS14O|7krR&NZZyV)ytVkk-g??vi zH%x8FQ{S3n;V2$1E39-DfY0SAAye$T8LNP6;bV+Wde1Ek_X#E~kL9pgd-Nq~H>AOp zORy=;;3MZw)X223cH~3xHcKSsM=n4h@{29jA!m7MM^0h*g1f_g@`>%<}b|O5|BQldu*bfBC zJe0OFksn$(D{XaAy*p_?)z6v^_E8Wn?eP!BMXa3hyL9-?BE)hRB>X9N^6WZr-8=n4 zAa}^>1?T4{jFo2aF6cXwpOMN7@9|aig>`%UGS10YkO^1kh9UF-F3f43qUz~)88cCM zEA(jTHQY?8tcaIk^&cS}tv(zQd)!%KT?eoySo$Mf1`|bkTs2_~qjtNN_)&@B_eAxb zACF_Th&(J?WSZ>s6C7#rB=v&waA&xY9#NlR$@Z^!GX@Z4d5P;PRH@Ro4<{aacs|4V zRrYgM+J$g+Cmvg<@U9bdKY3lw!N*L$AE;MIy&*o1yS(28-vq99eb4dyRc>nUt=lD` z;z`em>J9rV+8$nGBCKH4p=s5iw5wz9;ul{MVxR+IFO>6e)|&cR?YqT+_|K+Y)m2Ca zP>=;CFC$EL#Ov?_z#|0BhMmY~1SlIo9dZs%Aj5HGu33^#*rQ}fw-%U6pZY6%DN<2J zksfz+4m*i}=Yp&H;UL*CBns#-fX~~V!aIj>1{xi^m6?8eUgS||^arH|ir^y(l72+d zF>c9mKr59;aftQl`YcJ90fXRNJVw7bW|&Ge3Z2>)GAS15z!1%I_Jf|q^^l>Te$B%V z7Qb38=7e~QfKbp$K-=U&(jmPGNr1sRyS*|=e_i-zna!w4V)gEolGTl;$!0vI-hNc% z3WEq`>{~w!s2hx4gh-RAH&7%Ca_6W#5ILn7ODGMdTX0Y}-P#Lu1SiIp=rpB%voGJT zI=Fy2uj@hcB)!JL_l+lHPjYR$#)J2`Bz|G#w3cLGYiobf^rx9=h@jVuQn*Kk=apX( zO*YMa+f~b8RN~lx17qc2+X43E6(Bg?cDk1gFJ{A${kSj?apE3lHhT1US?5)_(Ba|< zIvi!0_vpS7C!_woHBQni!m!rYlFNy!Yy>^X>PE1`-paRTHks6^8P1_lSE9X&)yIwj z?H*+GmhOHh9Gr+6n#xh#T*@+c9O*oO9puCEwXXE{wc3%*HCj6R4Pz!!N47C^NJ`qG z{%n(1_QhZdMNlA%){XquRFgQIfblA;X{I;hdvf@mHwO37k^}RaOE@{pI>EF>x^T*4 zmcYHdTKnl9}aHMDh{sj7~#@HEY>D!GB|3zp;z%tfWT@=k)atD$Ez<4e-szKAQo!V>DO%4Ix%R10Q)#GCcxZfCB=OTuQx= zFxisbLs>7VTBLhxq0U@C%+fjE`Ga#tBt8%MG|lqX!eQIHzL^RIrH5#PohC>>^bdUY zUf1vKhH`F}>0SzS^_4D@rj%hv;nFV1pK*uQz8zGMI3|uBr265+WWC>Yz*RUUNJp@O z328kb5Q6wv&`5MLCcLH~B!p+w)z{3r{{h$YjkYHmqn+_R>)^dAXt=`Zn zd4TRNibs;&^KRyXgYmIT9o7a{#IBGHy;p?h_y(wDYxz->_JJVDa&Xajl`G;Ej%RpV zL{9|Be^-oxm$L(myWHMF+EqlhMUC97T9)?_ri=|}mVQHbyCz_s7G&qj7W+}0Qvnvl zv!5{`_29!P_t1ydV?W(p*p!cyt9{Gev$snkm;6O`DZ{LK7Q0-Q`rG=)ie2G^onz&o z9_#f9CGzVYH<^k(g+V|Jp#X05d=*Gk6K-jrwzWmDHqSjFLBVL!!5!z2K*Tb znlsG!HTK(_$bGld{?6+H(1^G#CNt5dg8^iyBv3K}^6--?BXO34Yi|H=Pqyv)`HG6u z-y~3Pb;(c}1T??UkEl2OBok>wlusbV|4p3;4P=^rIJ#sqk|YB?SL=k}taTw94DK}s z(asnhbww@_7s)D=HobHo`ZEWsip5$b#}h7M!D$K8U1{$)g{DiT`T`5Fmk20=r`7P| zU@4?_EZNy^2lxzr1`H!7S;nqhdd&z%c9PhKNfa$K|K}gaTkIYNJzN#sIKzvkCc|Sc z@mHowELsfO;3!M{z%U9z(~5Po!D$_ZnJabw@AxqILs&=CR)y5>r=|Wh(2hQ#jj}ii zhJregvYH*H_U=YJ)`I@+YHN6A6l4(^*^h_|RNw>`;MJ1g9Z~OHU6aDq zqZ}OSy*CkVR|2t_0|UZnKZcSk!#A9m&w3w_@-4*BK8wQjRr68ehl;1dNm{$cr5bDm z27U}+ca-7|*oKes4MiWYif}l_n>Cn%?Pq=-6R)cr$)poweiLexqtZeHwF0jZ31UIk z!c%$sMfJTnl;PeQgx^~ypYtjy3_1-`bm>peDwznPQodVQfAHb9p)3L`x%?e;=1U4! zLSP9uK)*KXKr(V7i}fZe9rzFd?_%1$GVZN}^~c}5Vf-vEB%oMfRz75dyeZh2je(>U zB?c9YkV<0jd`i5vwF~c+WX%sAhFnBpiEsB+J4F4l8%aDvutHaIs;7l}oOMpvr6fnV z@O~W|?y2(&T%LbjNs{YVkKhV7JPB&Q8AfOuJ_ci6l_t2wEKx zO^H8;__HBtoH08pp}V6mMgvh7o*tiuidIN>nK1fDviuZMMHqKEEchUy(MDgC24L(I z#@L!eS)f`k?J4vqX>!&R;pQDBO2geo{CGb1DO&B47$;a9#9cDy^UFuG;IVQ!&7P=B z-DZI{FfAyEv|E;qoZCp>VxdobI2gyjx;Pn^z~Qn!L zEeaKXut@6dRS3JTRDmzBzDNz0lIVWFS*|#6}Eq0z`ovmM#00` z0B(zBNV60?e_g$#%Vx?QIbCiw(?TJ@oaDHqFn4j5k%=;pXpG}&AIn=FY9f<`KAfiO z@Q0R)0N85;*e^e`<*uC~yQyxt*X)Hv`62X|-gZ&KL!yhQ*fg^6FaqID5A)3J{`VC& zNU@ZidCR`scEV97))?iCqcb1gT88yH@0QC;!SUEHATJHRGr32J$+Gsdm4f`Am-~|g zG^5=37Iex|2Hh7EB9j9k#8?D-dohN$+i+S$xx5X&{f%NYE4AM&j>N7_53VAI>$WF5 z96nK=Vj}#A6us?zuVjCA8uS$|4+CKy)~bE&{N23A5e2!R;Hj@6($cR#Z_id{Qv5BP z=SizcTFYX}b;r5Nf%ILG~~dy7(NfHDQv^>>);g;SQM0H8Xj2640OZF z0I6Rz_G2HglJX!$TM&0b&Du$0-$wXdrD+Cl-+V{_?|gwz;V=3TV377s=1UgQ4e9Sm z&eA?^d~8MrEA-I<2fT*xZdbT;oCM-yJSt_VE_j(|f#C0~59;B?9V;Cl9=t`@G zKF;Ku-Qi@=?;*&5tTO;D56h|&Z%vL?6WnpyW5R=>{G=Wtu9Jz!vg5=g28*W8?05Dq zkVr^?_+VqyYe$3zMuf4Y7QaHeFn``e_whFiDH3Yf`wwAF7GA~cqj$bK6lP9>s4W)^ zP}9w<6;rr3+{5F-+P)ll49B`{sr~82FkD=0oN5LH+CPff!gLv;J{G}!EkwIozC5?WOfNQMXAd1}hCvi?{mwoOxed1vY#dj8_wfP zG-W3$f{2*0Pgt*<&aT;1|7fx>DvpgVHXi3A#RUS&(7IsnkITMRts~O|U>SJ@)&HG9 zubDRte*If-YvT1dGdX&Fso`W#iv_4@17n$#Kttn5sjWSrb232U^73<@~|kQ2Ary$_%OQeJs4tSBSsmZv|lZ7 z&ccYG%Yv)f*BHlXJMkv(~ct!MB z))rY&DGs6YZt8`*tY-1l-0dKbmmD7QgP@84fN1<939%RH7Gp-Eo2CRy(0>3Pl~50O6XDauA22U-@FAAV}BC(K3{k(MoVZ& z&(ol+59wFs6)hC>jvjwrKTwfgdnjMl=1m+r&rQ)%mJ|s7PuIP&^eYKc5BLSP(vQyDFF3p!`Da7Kxk% zYnhFpY!Wi2e|7P^K6}Ux%aLs-(SBOx8c!enGL0wl&CbdgMi4H&JCUa4dw3}}BELXi zi7fHYQtZ1YsL7E%$x|&ZeW}`Y*G7uPeRuXx?%r#v9xpLGLx>Ay4G1Bd1+HEw(+Tx% z&7-Go{KeNRoU{GpYy9@GjF%)d#1l!R;1X#Fh{$!CdtcYulHoQuLewQaD`SXHVWGvQ zjRs$7uY&!j^n51^ZxOh9H9)==F#BL)Wam~J z?C;3MCr5!6c zlnxQ;=Un)NALlo}f1i0~zRaCFXMlV5xohvU*IMuWTKf>{F}|GS6wO)A7ex?8_e@Ra zKC5=gCaST;g0*M6Ps0AoldxON|xP~%uxREWaE zF_;tW^lR36iHlGwh=LLa5qKEJsxMMY!{Sa@>XNCyB6~w$H+)?Ewmwf06ppu<^KKhn zZ#7MP9^%oGvg+{rfsph-dZ$CQUDq*;m)hVg&GULRSTmJiv+b8Jb;Gc?m4YO__$Q5L zR@21W*K4{z$t>Uj`KyzcA~NpJQ&*O0A8eI3`8CbVtU0k~_2^6a&EBgbQ}bVLf=(|Z z3y!Axa(0H?XyTKQR3qf2-$sRB`#8CBgXrQBVNTUoP8zFDq+J=`Fd<1(cl!ttqx)0- z!)2^MxQwGmCmJG(Ila;f$VfE2Fzro=dQm6dk`j3z_F0Qeg33~}!V7#;9_Rv0ZfGVo zPVP0bzvzK@6GVz~sL*?8grXhJF)M<2>GEjrPqrXF4{~W^!yg9z06=JXU^EJ_^`dG- z|M&<}27oEREegLO{d+C{flUyXqz2fN{078bssG{*_f4Ek2&+|d{-{l;1Xv4z#lR+o z7Hz^YNUV{BoIc(hxQdgpdR^|)WPk$kn(fhiXcZ|LDrer)|5LcCX%xnQFao4WxNvcX zoUg#>tXB$Z*EOH7GIJIe+E5ige<5E*b#K7e)X>7E$L)PCB%_C_C}fb@jzlX8{2gpI90NYZFw$VGq_WKpGpvA0Hl#0&pNX zX*fv>^Fr+8*N!k+$@hQ%2jro+hI>NKbnVbh{D5@)^G-trvAvqvyNW+-ze*37_$5n|uvcSwW{kChfgHWIs^SOSB)rz*7p3_z;Z^weD-V70(Z z!5aTrScy)G{9hByd+HjKekLOB1B@VS%_3D%0q4CC(y6Wt&4Iz-^98!^6UAst{W{q9 zrxP!rd~q^Kbm2ZEt=niD3;<}FTowZqz)DQ=(B*~r)wFtxWO}@T0@u`BRansmjXJ}T zLAxhNy-1Og5sdKZ<@srd*ycp>ptJFnR@g+qX{!8J^!sJ!cO!-@qaI%3^7zafb1CrzvUkEDE=xIfk9tRN zd}V(tWcn3hZ^^Lph=+CBhM{st6uy=B6aPEg96x`b^DHzNC zOAM-?RI#&5bK#x-gyvk53I9GUQibE{0m+E?8z>BR|Sc+gc3(ZYj{~Zs04)13-@fGA=2(n947Oi4rAN zfm(}%oN7^48}(8!J$a|T(XNQ9trjc!WEne?ny6#R@Vt9}mB>{wfZm>rTT%0xn@21x zRlM7MjkO$?%1hEX@KnUu^{o`WXuz>N(XZP|%g2IM4%wY%1FN)*oALzwkJmnmSrQIXB{9ggrNnFoIQio`(;|meXWD7EY-W8*Qy2E1l)equ9QO6c8v0mlSak%GS-O0Xae)WM8JH^Ym^a6CRCs#a&F~ww zk>9P_siMzXs8Oxs2YhaFCWWo&%Y`bcLARlWdQ*p)+aNYLE3islgIwMxfHzmIt)$bh za^)<~PfWF{pxQ_(tSH+PdokNGz#wo%x=W{Wr2=gCq>t(D9L1!n`q8AL-g$EeFA)SR zIB;9yIYutsbb-%+eA}>Tkt$|)D#?a>yT2^gpL>4)mK>cp|I_0XK33uk2$Vw`?s^BI@{!d{%3Iu zW{(#1HPjf>?k=wxLXL~4#6sl4pP_$u`8C{`+uxY&Q{j8< znRsJovdkK{EG=jJ_6IbX%7)Ix)nowt4GBy0QGtZXLh!G-EtOn;^%xIT#9fVQn#US1 z;leQu}j3}3ezfRy-DoMMdhaCZ{n*`fFFpzzct=b2FiuDx3~}^go+%5(vv5h zSjc}~@vWt0=dDOwIvfu}c{IhMhpp5~Hs8IU7P-xhZ zb{Xdqax*#d4bw#wTA!oh`C}BepNlW}iB)Fb2fx@MY_2@R<#|hp@VT z*3w4x1FO9Wp@Uiqz#^^6za?RD{ zoaOoPPbBtffMP1vYC!I*47&mEN;`UH@i~4q?O}U|p3~UKO5F1Ey&y8g7kvy1Y`TRG zs~3gs1S>zD%h=9j<*xgQL0_+eR04#-k}k)Qys!Fg0D3mzLP2YQb{`ij7GXELOCFac z@-u^`?E0BQWBepBSi4NzXkFyQbtk*+JbmiOdsx4{hlO0&b<%qBX)Ial24g{1c%w@n zdML`4+kQB_^)_ZmTC;-U=C(QfJtN0!KmV{^fMT6*mfqo?K>nszui(WjP_Wp z`f%!gz7)KZJz%CCx`{)%;yFUVOv>9&lq@a{b(sJlV{J(cMYiM|uJxdJ(+;~?{t~Nt zF+Zq*W7^@&1s0%GB%Z+NkRHvcifwp_a;Z&2ZabInhz2~BFf7YykvId>f z4|AR%gZ+}6iiQCa&0uQ7$nYk7Y&7(7eBwLZPHUMJgK1H^(xRaO8B@s&>^z*yh+K{n zKdgO*a=H}B4rWK}?5}`=6@x1?wh5prTU+cG#4429eJ*}kh*ta~}+H31Xiz%2nZ!;m1#7y=u{xJN%ZEHsEnEXaRA# zi1g4jQy2Sj>2yKpM%>Ur2;1eU-U{SOw2lZ{s>+?$mT!c8o!VY#&18|dG{+wyn11Ek zJb)A<@i7o+#oJ!r@aHCX3K}DV0^>Pg54$736YZ;zn~bjR;<&x{X>xR$l5Rb}6uYq7 zGANW@C3Kp9zH@rA8Ph7t5bv>s&pR`q{kS;>5@Nwn26B7@s*XOliR8EoF!bH>DRrzN zY!sIYwM6E;Jv0kVD0RNrMG7<^fz@etWJ1Y{FLGxv@{jUJ5RVv0rBB_(h@do4t2e6H z(RAdBAU+~1$Ft-6ykaUg;J*JP`;|Qfgzbt!W%c}al&dHuc>a=Y=8c}ja$}YfoozGn z^WAYQ_9;*^u_>VW#}Q@59s-CuzT7d# z(*AAPVXb7qb6UU4`ab`j}eK(KS-F9-l?G z*rgaB6k1EW8Puk~+a_Pqj4t&?VC~~^RibW2I>zyKlkIF@t6d6cCUyoNQ{iq7C9WTW zMXPU6jgaS44wF0$^=>{q{4RuBb}%aX{1I89|K;KySmA>KrX_atiAZ+h?tP?+3&#=u z1I=&z!lZ%kxiS+=#A~~!m#0el9^YNu-qlZqh_EiMEla5p1Pn;~86Ql8xGR*oBC)WU zHOh5lTfh0p3xlRv(kH21<2t)NilV2t&kE0%v0jj`d>0;ZljFSIjux<7VjnSn`mAR8 zEjw%2y-y6^l@{Z^sJ=7r0XBG49HQ<#uS&5@zq=35Igq+BdDW=#z1xMx+W9fRm~vUk zv&&5cOWOfk@5bj;3vXte6Aii0f04MHGQlT|urQ@!U7IzfJflOD2-3vMj_QJ$p_YW_ zwsU7{XJ=xA874igjbB>uW7Faoh*QY+M7{S8DNyR>?0S!SZNfnYfvCQS*_B%FvbyDx zFyTj+d3G!!0fuvO)Y^)nRY=Tu{`&jrn31P3WwbYkxca@(lHfS_k@F|@T?d9DfRXB& zqTU-N*C21XQIIO21apDkGfm(a zOCnHSLz;)19sGx)p##WP@KH2_{|H$SO$8eJH6kErP!*(mCH!%s_f&wOp+lpKexIZL z)3~@aW*#;k*6>giq;T}N7a~5Oa=oYOcZPh`-(FO�OqC4?Hp0_+Cd~ao)KOF#Ih~ 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 B#3BFy literal 52369 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%0D>iEp0(}z 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 Date: Thu, 24 Apr 2025 11:11:59 +0300 Subject: [PATCH 18/26] Update README.md --- README.md | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ea151962..b2bcc127 100644 --- a/README.md +++ b/README.md @@ -274,6 +274,10 @@ Setting up OpenID Connect has 3 separate parts: - Configuring Identity Mappings with Claim rules, matching to Projects & Service Connections. - Configuring Service Connections as OpenID Connect in the Projects in your Azure Devops Instance. +> [!IMPORTANT] +> To use OIDC authentication, make sure you're using **JFrog CLI version 2.75.0 or later** +> and **JFrog Azure DevOps Extension version 2.11.0 or later**. + Follow the guides below to configure each part.
@@ -385,29 +389,31 @@ This requires you to fill in the following inputs: | Description (optional) | A short of the purpose of this ServiceConnection | -> **Tip**: When using JFrog CLI version `2.75.0` or later, the extension automatically exports the authenticated user and access token +> [!TIP] +> When using JFrog CLI version `2.75.0` or later, the extension automatically exports the authenticated user and access token > as step outputs named `oidc_user` and `oidc_token`. These outputs can be used in later steps (e.g., for Docker login, Helm registry, or custom scripts). > +> If you override the CLI version in your pipeline and use an older version, these outputs may not be available. +> > Example usage in a later step: > - ```yaml -steps: -- task: JfrogCliV2@1 - name: jfStep - inputs: - jfrogPlatformConnection: 'azure-oidc' - command: 'jf rt ping' - -- task: PowerShell@2 - inputs: - targetType: 'inline' - script: | - echo "OIDC Username (from output): $(jfStep.oidc_user)" - echo "OIDC Token (from env): $env:oidc_token" - displayName: 'Use OIDC Output Variables' +> ```yaml +> steps: +> - task: JfrogCliV2@1 +> name: jfStep +> inputs: +> jfrogPlatformConnection: 'azure-oidc' +> command: 'jf rt ping' +> +> - task: PowerShell@2 +> inputs: +> targetType: 'inline' +> script: | +> echo "OIDC Username (from output): $(jfStep.oidc_user)" +> echo "OIDC Token (from env): $env:oidc_token" +> displayName: 'Use OIDC Output Variables' > ``` - A sample configuration would look like this: ![oidc-service-connection.png](images/oidc-service-connection.png) From acead34aece3f0738e5a3fcf7c25dc40a67e4a75 Mon Sep 17 00:00:00 2001 From: delarea Date: Thu, 24 Apr 2025 11:16:12 +0300 Subject: [PATCH 19/26] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b2bcc127..8f8d9328 100644 --- a/README.md +++ b/README.md @@ -389,12 +389,11 @@ This requires you to fill in the following inputs: | Description (optional) | A short of the purpose of this ServiceConnection | + > [!TIP] > When using JFrog CLI version `2.75.0` or later, the extension automatically exports the authenticated user and access token > as step outputs named `oidc_user` and `oidc_token`. These outputs can be used in later steps (e.g., for Docker login, Helm registry, or custom scripts). -> > If you override the CLI version in your pipeline and use an older version, these outputs may not be available. -> > Example usage in a later step: > > ```yaml @@ -412,8 +411,9 @@ This requires you to fill in the following inputs: > echo "OIDC Username (from output): $(jfStep.oidc_user)" > echo "OIDC Token (from env): $env:oidc_token" > displayName: 'Use OIDC Output Variables' -> ``` - +> ```yaml +> +> A sample configuration would look like this: ![oidc-service-connection.png](images/oidc-service-connection.png) From a516f98b5a8cdc26581ff287048184e139c20469 Mon Sep 17 00:00:00 2001 From: delarea Date: Thu, 24 Apr 2025 11:17:28 +0300 Subject: [PATCH 20/26] Update README.md --- README.md | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8f8d9328..b1bc8770 100644 --- a/README.md +++ b/README.md @@ -389,6 +389,11 @@ This requires you to fill in the following inputs: | Description (optional) | A short of the purpose of this ServiceConnection | +A sample configuration would look like this: + +![oidc-service-connection.png](images/oidc-service-connection.png) + +Now this Service Connection can be used for any of JFrog tasks as normal, authenticating with a temporary access token each time the pipeline runs. > [!TIP] > When using JFrog CLI version `2.75.0` or later, the extension automatically exports the authenticated user and access token @@ -411,18 +416,8 @@ This requires you to fill in the following inputs: > echo "OIDC Username (from output): $(jfStep.oidc_user)" > echo "OIDC Token (from env): $env:oidc_token" > displayName: 'Use OIDC Output Variables' -> ```yaml -> -> -A sample configuration would look like this: -![oidc-service-connection.png](images/oidc-service-connection.png) - -Now this Service Connection can be used for any of JFrog tasks as normal, authenticating with a temporary access token each time the pipeline runs. -> **Note**: OpenID Connect authentication requires JFrog CLI version `2.75.0` or higher. -> If your pipeline uses an earlier version (e.g., by overriding the CLI version via environment variable or custom installation), -> the authentication may fail or not support the full feature set (such as step outputs). See [JFrog CLI - OIDC Token Exchange (`jf eot`)](https://jfrog.com/help/r/jfrog-cli/jfrog-cli-eot) for more information on how the CLI handles OpenID Connect tokens behind the scenes. From dc77c62f77ef063b679b6dbfb8c97835295f3a30 Mon Sep 17 00:00:00 2001 From: delarea Date: Thu, 24 Apr 2025 11:18:31 +0300 Subject: [PATCH 21/26] Update README.md --- README.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index b1bc8770..ff7a070d 100644 --- a/README.md +++ b/README.md @@ -400,22 +400,23 @@ Now this Service Connection can be used for any of JFrog tasks as normal, authen > as step outputs named `oidc_user` and `oidc_token`. These outputs can be used in later steps (e.g., for Docker login, Helm registry, or custom scripts). > If you override the CLI version in your pipeline and use an older version, these outputs may not be available. > Example usage in a later step: -> -> ```yaml -> steps: -> - task: JfrogCliV2@1 -> name: jfStep -> inputs: -> jfrogPlatformConnection: 'azure-oidc' -> command: 'jf rt ping' -> -> - task: PowerShell@2 -> inputs: -> targetType: 'inline' -> script: | -> echo "OIDC Username (from output): $(jfStep.oidc_user)" -> echo "OIDC Token (from env): $env:oidc_token" -> displayName: 'Use OIDC Output Variables' + + ```yaml + steps: + - task: JfrogCliV2@1 + name: jfStep + inputs: + jfrogPlatformConnection: 'azure-oidc' + command: 'jf rt ping' + + - task: PowerShell@2 + inputs: + targetType: 'inline' + script: | + echo "OIDC Username (from output): $(jfStep.oidc_user)" + echo "OIDC Token (from env): $env:oidc_token" + displayName: 'Use OIDC Output Variables' + ``` From c2d71f67d2fe42e3b1fa394046c3fc7fbdf31272 Mon Sep 17 00:00:00 2001 From: delarea Date: Thu, 24 Apr 2025 11:19:31 +0300 Subject: [PATCH 22/26] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ff7a070d..951a6215 100644 --- a/README.md +++ b/README.md @@ -401,7 +401,8 @@ Now this Service Connection can be used for any of JFrog tasks as normal, authen > If you override the CLI version in your pipeline and use an older version, these outputs may not be available. > Example usage in a later step: - ```yaml + +```yaml steps: - task: JfrogCliV2@1 name: jfStep @@ -416,7 +417,7 @@ Now this Service Connection can be used for any of JFrog tasks as normal, authen echo "OIDC Username (from output): $(jfStep.oidc_user)" echo "OIDC Token (from env): $env:oidc_token" displayName: 'Use OIDC Output Variables' - ``` +``` From 3492d4e0408ea77ada27e067ff96b340e71989fd Mon Sep 17 00:00:00 2001 From: delarea Date: Thu, 24 Apr 2025 11:20:01 +0300 Subject: [PATCH 23/26] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 951a6215..b5813c20 100644 --- a/README.md +++ b/README.md @@ -395,7 +395,7 @@ A sample configuration would look like this: Now this Service Connection can be used for any of JFrog tasks as normal, authenticating with a temporary access token each time the pipeline runs. -> [!TIP] +> [!IMPORTANT] > When using JFrog CLI version `2.75.0` or later, the extension automatically exports the authenticated user and access token > as step outputs named `oidc_user` and `oidc_token`. These outputs can be used in later steps (e.g., for Docker login, Helm registry, or custom scripts). > If you override the CLI version in your pipeline and use an older version, these outputs may not be available. From bfbe0d2fd02497ee5412c5ec4bcc4abbcf6b1315 Mon Sep 17 00:00:00 2001 From: delarea Date: Thu, 24 Apr 2025 11:26:38 +0300 Subject: [PATCH 24/26] Update README.md --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b5813c20..8d2d836e 100644 --- a/README.md +++ b/README.md @@ -395,13 +395,11 @@ A sample configuration would look like this: Now this Service Connection can be used for any of JFrog tasks as normal, authenticating with a temporary access token each time the pipeline runs. -> [!IMPORTANT] -> When using JFrog CLI version `2.75.0` or later, the extension automatically exports the authenticated user and access token +> 💡 **Tip** +> The extension automatically exports the authenticated user and access token > as step outputs named `oidc_user` and `oidc_token`. These outputs can be used in later steps (e.g., for Docker login, Helm registry, or custom scripts). -> If you override the CLI version in your pipeline and use an older version, these outputs may not be available. > Example usage in a later step: - ```yaml steps: - task: JfrogCliV2@1 @@ -420,8 +418,6 @@ Now this Service Connection can be used for any of JFrog tasks as normal, authen ``` - - See [JFrog CLI - OIDC Token Exchange (`jf eot`)](https://jfrog.com/help/r/jfrog-cli/jfrog-cli-eot) for more information on how the CLI handles OpenID Connect tokens behind the scenes.
From 1173138daacb65c1726a4c4ad1d1a32c9dd67fc7 Mon Sep 17 00:00:00 2001 From: delarea Date: Sun, 4 May 2025 13:05:40 +0300 Subject: [PATCH 25/26] Update README.md --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8d2d836e..94cce676 100644 --- a/README.md +++ b/README.md @@ -288,13 +288,14 @@ Follow the guides below to configure each part. -First you must configure your JFrog instance to have an OpenID Connect integration to your Azure DevOps server. -Login to your JFrog instance as an Administrator, then as [described in the documentation:](https://jfrog.com/help/r/jfrog-platform-administration-documentation/openid-connect-configurations-overview) +First, configure an OpenID Connect integration to your Azure DevOps server in your JFrog instance. +Log in to your JFrog instance as an administrator, +then as [described in the documentation:](https://jfrog.com/help/r/jfrog-platform-administration-documentation/openid-connect-configurations-overview) -1. Go to the Administrator panel. -2. Select General Management. -3. Choose Manage Integrations. -4. Select New Integration - OpenID Connect +1. Go to the **Administrator panel**. +2. Select **General Management**. +3. Choose **Manage Integrations**. +4. Select New Integration - **OpenID Connect** Now fill out the integration with the parameters of your Azure DevOps instance. @@ -307,13 +308,13 @@ Now fill out the integration with the parameters of your Azure DevOps instance. | Audience | example: `api://AzureADTokenExchange` | | Token Issuer | If the issuer is different from the provider, for Azure DevOps this can be left blank. | -As an example the final integration configuration will look like: +For example, the final integration configuration will look like this: ![oidc-integration.png](images/oidc-integration.png) In order to obtain your Azure DevOps Organization GUID (`{ORG_GUID}`) you can simply run a pipeline in your Azure DevOps organization using any of the JFrog Task setup using a Service Connection configured with the `OpenID Connect Integration` authentication method, see the [Configure the Service Connection](#configure-the-service-connection) section. Even if the task fails due to you not yet having configured the Integration in JFrog, it will output the relevant information as part of the pipeline. -In the Pipeline Output, look for the `OIDC Token Issuer`, this value is what you must put in as your `Provider URL`. +In the Pipeline Output, look for the `OIDC Token Issuer`,value, which you need to enter as your `Provider URL`. The rest of the information can also be helpful for you to configure the Identity Mappings as described in the section below. ``` @@ -376,7 +377,6 @@ Just make sure to never replace your Organization name with a `*` operator as th You must configure a `ServiceConnection` setting the `Authentication method` to `OpenID Connect Integration`. -All four types of Service Connections are supported, they will all require the same input regardless of the type. This requires you to fill in the following inputs: From 0380a294ef6f540d7db79e7e1692c867a9acc77f Mon Sep 17 00:00:00 2001 From: delarea Date: Sun, 4 May 2025 13:09:55 +0300 Subject: [PATCH 26/26] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 94cce676..8695b826 100644 --- a/README.md +++ b/README.md @@ -297,7 +297,7 @@ then as [described in the documentation:](https://jfrog.com/help/r/jfrog-platfor 3. Choose **Manage Integrations**. 4. Select New Integration - **OpenID Connect** -Now fill out the integration with the parameters of your Azure DevOps instance. +Next, fill out the integration form with your Azure DevOps instance parameters. | Property name | Description | | ------------- |---------------------------------------------------------------------------------------|