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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions Documentation/OneLocBuild.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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. |
Expand Down
58 changes: 12 additions & 46 deletions Documentation/OneLocBuildGitHubApp.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand Down Expand Up @@ -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). |
Expand All @@ -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
Expand All @@ -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`**.
44 changes: 15 additions & 29 deletions eng/common/core-templates/job/onelocbuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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 }}"
Expand Down Expand Up @@ -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
Comment thread
missymessa marked this conversation as resolved.

- ${{ if ne(parameters.SkipLocProjectJsonGeneration, 'true') }}:
- task: Powershell@2
Expand All @@ -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 }}
Expand Down Expand Up @@ -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 }}
Expand Down
Loading