diff --git a/Documentation/OneLocBuild.md b/Documentation/OneLocBuild.md index 0bf8bd0e802..bd015bed730 100644 --- a/Documentation/OneLocBuild.md +++ b/Documentation/OneLocBuild.md @@ -67,7 +67,9 @@ that the official build is based on. As a further note, the template by default assumes that your mirror repository is located in the dotnet GitHub organization. If that is not the case, you will need to specify `GitHubOrg` as well. -If the repo is not in the dotnet organization, dotnet-bot may need to be granted additional permissions to interact with your repository. Invite dotnet-bot (Go to the repository's "Settings" then click "Collaborators" in the left menu). After the invite has been sent, reach out to the "First Responders" [channel](https://teams.microsoft.com/l/channel/19%3Aafba3d1545dd45d7b79f34c1821f6055%40thread.skype/First%20Responders?groupId=4d73664c-9f2f-450d-82a5-c2f02756606d&tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47) and ask them to accept the "dotnet bot" collaboration invite. To accept the invite, the first responder will need to [login](https://dev.azure.com/dnceng/internal/_wiki/wikis/DNCEng%20Services%20Wiki/869/How-to-log-into-a-GitHub-bot-in-Key-Vault) as dotnet bot, go to the inviting repository, and then accept the invitation which should appear. +If the repo is not in the dotnet organization, the `dotnet OneLoc Localization` GitHub App must +be installed for that organization and granted access to the repository. Follow the +[OneLocBuild GitHub App instructions](OneLocBuildGitHubApp.md). 8. Merge the changes to your main branch and then open a [repo modification ticket](https://aka.ms/ceChangeLocConfig) @@ -200,10 +202,8 @@ The parameters that can be passed to the template are as follows: | `LanguageSet` | `VS_Main_Languages` | This defines the `LanguageSet` of the LocProject.json as described in the [OneLocBuild task documentation](https://dev.azure.com/ceapex/CEINTL/_wiki/wikis/CEINTL.wiki/107/Localization-with-OneLocBuild-Task?anchor=languageset%2C-languages-(required)). | | `LclSource` | `LclFilesInRepo` | This passes the `LclSource` input to the OneLocBuild task as described in [its documentation](https://dev.azure.com/ceapex/CEINTL/_wiki/wikis/CEINTL.wiki/107/Localization-with-OneLocBuild-Task?anchor=languageset%2C-languages-(required)). For most repos, this should be set to `LclFilesfromPackage`. | | `LclPackageId` | `''` | When `LclSource` is set to `LclFilesfromPackage`, this passes in the package ID as described in the [OneLocBuild task documentation](https://dev.azure.com/ceapex/CEINTL/_wiki/wikis/CEINTL.wiki/107/Localization-with-OneLocBuild-Task?anchor=scenario-2%3A-lcl-files-from-a-package). | -| `CeapexServiceConnection` | `'dnceng-onelocbuild-ceapex'` | The project-scoped WIF service connection used to acquire a short-lived token for the Ceapex feeds. This path is enabled in `dnceng/internal` and `DevDiv/DevDiv`; other projects continue to use `CeapexPat`. Pipelines in either supported project must be authorized to use their project's connection. Set to `''` to explicitly use the PAT path. | -| `UseGitHubAppAuthentication` | `true` | Use GitHub App authentication for the check-in PR. The App path is enabled by default in `dnceng/internal` and `DevDiv/DevDiv`; other projects must also set `UseGitHubAppAuthenticationInOtherProjects`. Set to `false` to temporarily use the PAT path. See [the GitHub App doc](OneLocBuildGitHubApp.md). | -| `UseGitHubAppAuthenticationInOtherProjects` | `false` | Explicitly enable the App path outside `dnceng/internal` and `DevDiv/DevDiv`. The project must have its own WIF service connection with signing access, supplied through `GitHubAppServiceConnection`. | -| `GitHubAppServiceConnection` | `'dnceng-oneloc-githubapp'` | The dnceng/internal WIF service connection used to sign the App JWT. When the value remains the `dnceng-oneloc-githubapp` default, Arcade automatically uses `devdiv-oneloc-githubapp` in `DevDiv/DevDiv`; overrides to a different value are preserved for separately provisioned infrastructure. | +| `CeapexServiceConnection` | `'dnceng-onelocbuild-ceapex'` | The project-scoped WIF service connection used to acquire a short-lived token for the Ceapex feeds. OneLocBuild supports only `dnceng/internal` and `DevDiv/DevDiv`; pipelines must be authorized to use the connection. | +| `GitHubAppServiceConnection` | `'dnceng-oneloc-githubapp'` | The dnceng/internal WIF service connection used to sign the App JWT. When the value remains the default, Arcade automatically uses `devdiv-oneloc-githubapp` in `DevDiv/DevDiv`. | | `GitHubAppClientId` | `'Iv23lijBU8x3gc9lDOc9'` | The GitHub App's Client ID. | | `GitHubAppKeyVaultName` | `'EngKeyVault'` | Key Vault holding the App's RSA signing key. | | `GitHubAppKeyName` | `'oneloc-localization-app-key'` | Name of the App's RSA signing key in the Key Vault. | diff --git a/Documentation/OneLocBuildGitHubApp.md b/Documentation/OneLocBuildGitHubApp.md index 6ae04040d9d..302480e3894 100644 --- a/Documentation/OneLocBuildGitHubApp.md +++ b/Documentation/OneLocBuildGitHubApp.md @@ -18,24 +18,15 @@ job is to open/update the localization check-in PR on your repository. ## How it works -The App path is enabled by default. In -[`onelocbuild.yml`](/eng/common/core-templates/job/onelocbuild.yml), the App token is minted only -when **all** of the following are true: - -- `UseGitHubAppAuthentication` is `true` (the default), **and** -- `RepoType` is `gitHub`, **and** -- the build is running in the **`dnceng/internal`** or **`DevDiv/DevDiv`** Azure DevOps project, or - `UseGitHubAppAuthenticationInOtherProjects` is explicitly set to `true` for a separately - provisioned service connection. +In [`onelocbuild.yml`](/eng/common/core-templates/job/onelocbuild.yml), the App token is minted +whenever `RepoType` is `gitHub`. OneLocBuild supports the **`dnceng/internal`** and +**`DevDiv/DevDiv`** Azure DevOps projects. When those hold, the job runs [`get-github-app-token.yml`](/eng/common/core-templates/steps/get-github-app-token.yml), which signs a JWT with the App's RSA key in Key Vault, exchanges it for an installation token, and passes that token to the OneLocBuild task via `gitHubPatVariable`. -If `UseGitHubAppAuthentication` is explicitly set to `false`, or a project outside the two -supported projects does not explicitly opt in, the job uses the existing `GithubPat` parameter. This is a -template-selection fallback only: if App token minting or authentication fails after the App path -is selected, the job fails and does not retry with the PAT. +If App token minting or authentication fails, the job fails; there is no stored-PAT fallback. ## Gaining access @@ -44,13 +35,11 @@ is selected, the job fails and does not retry with the PAT. 1. **The App must be installed on the GitHub org/account that owns your target repo, and your specific repository must be selected in that installation.** The App can only open a PR against a repository it is installed on. This is what actually grants the App permission to your repo. -2. **Your pipeline must use the App path.** In `dnceng/internal` and `DevDiv/DevDiv`, leave - `UseGitHubAppAuthentication` set to `true`. In another project, provision a project-scoped - service connection and explicitly opt in as described below. +2. **Your pipeline must run in `dnceng/internal` or `DevDiv/DevDiv` and be authorized to use that + project's App service connection.** -The .NET Engineering Services team manages the App signing key. Contact the First Responders before -enabling another Azure DevOps project so they can provision or approve a least-privilege WIF service -connection and authorize the intended pipeline. +The .NET Engineering Services team manages the App signing key and the project-scoped service +connections. Contact the First Responders to authorize an intended pipeline. ### Step 1 — Request that your repository be added to the App installation @@ -93,32 +82,13 @@ Arcade automatically selects the project-scoped service connection: | `DevDiv/DevDiv` | `devdiv-oneloc-githubapp` | The App client ID, Key Vault, and key name are also centralized in the Arcade template. A pipeline -still needs one-time authorization to use its project's connection. It can temporarily set -`UseGitHubAppAuthentication: false` to select the PAT path instead. - -For a pipeline outside `dnceng/internal` and `DevDiv/DevDiv`, keep using the wrapper appropriate for that pipeline -(`templates/job` or `templates-official/job`) and explicitly select its project-scoped connection. -This example uses the official wrapper: - -```yaml -- template: /eng/common/templates-official/job/onelocbuild.yml - parameters: - LclSource: lclFilesfromPackage - LclPackageId: 'LCL-JUNO-PROD-YOURREPO' - UseGitHubAppAuthenticationInOtherProjects: true - GitHubAppServiceConnection: 'your-project-oneloc-githubapp' -``` - -The service connection identity needs the `Key Vault Crypto User` role on the App signing key, and -the pipeline must be authorized to use the connection. +still needs one-time authorization to use its project's connection. ### GitHub App parameters | **Parameter** | **Default** | **Notes** | |:-:|:-:|-| -| `UseGitHubAppAuthentication` | `true` | Activates the App path for GitHub repos in `dnceng/internal` and `DevDiv/DevDiv`, or in another project that explicitly opts in. Set to `false` to select the PAT path. | -| `UseGitHubAppAuthenticationInOtherProjects` | `false` | Explicitly activates the App path outside `dnceng/internal` and `DevDiv/DevDiv`. Requires separately provisioned infrastructure. | -| `GitHubAppServiceConnection` | `'dnceng-oneloc-githubapp'` | The Azure DevOps **WIF service connection** used by `dnceng/internal` and explicit opt-ins. When the value remains the `dnceng-oneloc-githubapp` default, Arcade selects `devdiv-oneloc-githubapp` automatically in `DevDiv/DevDiv`; overrides to a different value are preserved. | +| `GitHubAppServiceConnection` | `'dnceng-oneloc-githubapp'` | The Azure DevOps **WIF service connection** used by `dnceng/internal`. When the value remains the default, Arcade selects `devdiv-oneloc-githubapp` automatically in `DevDiv/DevDiv`. | | `GitHubAppClientId` | `'Iv23lijBU8x3gc9lDOc9'` | The GitHub App's **Client ID** (used as the JWT `iss` claim). | | `GitHubAppKeyVaultName` | `'EngKeyVault'` | The Key Vault holding the App's RSA signing key. | | `GitHubAppKeyName` | `'oneloc-localization-app-key'` | The name of the RSA key inside that Key Vault (the App's private key). | @@ -136,9 +106,7 @@ The token is minted for the installation on the `GitHubOrg` account (default `do ## Troubleshooting -- **The App-token step is skipped.** The App path only activates when - `UseGitHubAppAuthentication` is `true`, `RepoType` is `gitHub`, and the build runs in - `dnceng/internal`, `DevDiv/DevDiv`, or explicitly sets `UseGitHubAppAuthenticationInOtherProjects: true`. +- **The App-token step is skipped.** The App path activates when `RepoType` is `gitHub`. - **The pipeline pauses for service-connection authorization.** Authorize the pipeline to use `dnceng-oneloc-githubapp` in `dnceng/internal` or `devdiv-oneloc-githubapp` in `DevDiv/DevDiv`. - **Token minting fails with a Key Vault authorization error.** The service connection identity @@ -151,6 +119,4 @@ The token is minted for the installation on the `GitHubOrg` account (default `do ## Scope and limitations -- Arcade has project-scoped defaults for **`dnceng/internal`** and **`DevDiv/DevDiv`**. - Pipelines in other projects use `GithubPat` unless they explicitly opt in with a project-scoped - service connection and signing-key access. +- Arcade supports OneLocBuild in **`dnceng/internal`** and **`DevDiv/DevDiv`**. diff --git a/eng/common/core-templates/job/onelocbuild.yml b/eng/common/core-templates/job/onelocbuild.yml index e4e6b77fc36..70901aca26e 100644 --- a/eng/common/core-templates/job/onelocbuild.yml +++ b/eng/common/core-templates/job/onelocbuild.yml @@ -5,19 +5,10 @@ parameters: # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool pool: '' - CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex - GithubPat: $(BotAccount-dotnet-bot-repo-PAT) - - # Service connection for WIF-based Entra authentication to ceapex feeds (replaces CeapexPat). - # dnceng/internal and DevDiv/DevDiv have same-named, project-scoped connections. Other projects, - # and any pipeline that sets this to '', fall back to PAT-based auth via the CeapexPat parameter. + # Project-scoped WIF service connection for Ceapex feed authentication. CeapexServiceConnection: 'dnceng-onelocbuild-ceapex' # GitHub App authentication for the OneLoc check-in PR. - # dnceng/internal and DevDiv/DevDiv are enabled by default with their project-scoped service - # connections. Other projects must explicitly opt in after provisioning equivalent infrastructure. - UseGitHubAppAuthentication: true - UseGitHubAppAuthenticationInOtherProjects: false GitHubAppServiceConnection: 'dnceng-oneloc-githubapp' GitHubAppClientId: 'Iv23lijBU8x3gc9lDOc9' GitHubAppKeyVaultName: 'EngKeyVault' @@ -49,7 +40,6 @@ jobs: displayName: OneLocBuild${{ parameters.JobNameSuffix }} variables: - - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat - name: _GenerateLocProjectArguments value: -SourcesDirectory ${{ parameters.SourcesDirectory }} -LanguageSet "${{ parameters.LanguageSet }}" @@ -80,6 +70,10 @@ jobs: steps: - ${{ if eq(parameters.is1ESPipeline, '') }}: - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error + - ${{ if notIn(variables['System.TeamProject'], 'internal', 'DevDiv') }}: + - 'OneLocBuild is supported only in dnceng/internal and DevDiv/DevDiv.': error + - ${{ if eq(parameters.CeapexServiceConnection, '') }}: + - 'CeapexServiceConnection must identify a WIF service connection.': error - ${{ if ne(parameters.SkipLocProjectJsonGeneration, 'true') }}: - task: Powershell@2 @@ -89,17 +83,15 @@ jobs: displayName: Generate LocProject.json condition: ${{ parameters.condition }} - # Acquire an Entra token for ceapex feed access in the supported internal and DevDiv projects. - - ${{ if and(ne(parameters.CeapexServiceConnection, ''), or(eq(variables['System.TeamProject'], 'internal'), eq(variables['System.TeamProject'], 'DevDiv'))) }}: - - template: /eng/common/templates/steps/get-federated-access-token.yml - parameters: - federatedServiceConnection: ${{ parameters.CeapexServiceConnection }} - outputVariableName: 'CeapexEntraToken' - condition: ${{ parameters.condition }} + # Acquire a short-lived Entra token for Ceapex feed access. + - template: /eng/common/templates/steps/get-federated-access-token.yml + parameters: + federatedServiceConnection: ${{ parameters.CeapexServiceConnection }} + outputVariableName: 'CeapexEntraToken' + condition: ${{ parameters.condition }} - # Mint a short-lived GitHub App installation token for the loc check-in PR. Use the connection - # provisioned in each supported project; other projects must explicitly opt in and override it. - - ${{ if and(eq(parameters.RepoType, 'gitHub'), eq(parameters.UseGitHubAppAuthentication, true), or(eq(variables['System.TeamProject'], 'internal'), eq(variables['System.TeamProject'], 'DevDiv'), eq(parameters.UseGitHubAppAuthenticationInOtherProjects, true))) }}: + # Mint a short-lived GitHub App installation token for the loc check-in PR. + - ${{ if eq(parameters.RepoType, 'gitHub') }}: - template: /eng/common/core-templates/steps/get-github-app-token.yml parameters: is1ESPipeline: ${{ parameters.is1ESPipeline }} @@ -129,16 +121,10 @@ jobs: isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }} isShouldReusePrSelected: ${{ parameters.ReusePr }} packageSourceAuth: patAuth - ${{ if and(ne(parameters.CeapexServiceConnection, ''), or(eq(variables['System.TeamProject'], 'internal'), eq(variables['System.TeamProject'], 'DevDiv'))) }}: - patVariable: $(CeapexEntraToken) - ${{ if or(eq(parameters.CeapexServiceConnection, ''), and(ne(variables['System.TeamProject'], 'internal'), ne(variables['System.TeamProject'], 'DevDiv'))) }}: - patVariable: ${{ parameters.CeapexPat }} + patVariable: $(CeapexEntraToken) ${{ if eq(parameters.RepoType, 'gitHub') }}: repoType: ${{ parameters.RepoType }} - ${{ if and(eq(parameters.UseGitHubAppAuthentication, true), or(eq(variables['System.TeamProject'], 'internal'), eq(variables['System.TeamProject'], 'DevDiv'), eq(parameters.UseGitHubAppAuthenticationInOtherProjects, true))) }}: - gitHubPatVariable: "$(GitHubAppInstallationToken)" - ${{ else }}: - gitHubPatVariable: "${{ parameters.GithubPat }}" + gitHubPatVariable: "$(GitHubAppInstallationToken)" ${{ if ne(parameters.MirrorRepo, '') }}: isMirrorRepoSelected: true gitHubOrganization: ${{ parameters.GitHubOrg }}