Changes to nuget functionality (#856)

With this release the implementation for delivering to NuGet packages
(by adding the NuGetContext secret), is similar to the functionality
behind delivering to GitHub packages and the implementation is final.

New Settings:
- `trustMicrosoftNuGetFeeds` Unless this setting is set to false, AL-Go
for GitHub will trust the NuGet feeds provided by Microsoft. The feeds
provided by Microsoft contains all Microsoft apps, all Microsoft symbols
and symbols for all AppSource apps.
- `trustedNuGetFeeds` - can be an array of NuGet feed specifications,
which AL-Go for GitHub will use for dependency resolution. Every feed
specification must include a url property and can optionally include a
few other properties:
- Url - The URL of the feed (examples:
https://pkgs.dev.azure.com/myorg/apps/\_packaging/myrepo/nuget/v3/index.json
or https://nuget.pkg.github.com/mygithuborg/index.json")
- Patterns - AL-Go for Github will only trust packages, where the ID
matches this pattern. Default is all packages (\*).
- FingerPrints - If specified, AL-Go for GitHub will only trust packages
signed with one of the fingerprints specified in this array of
fingerprints.
- AuthTokenSecret - If the NuGet feed specified by URL is private, the
authTokenSecret must be the name of a secret containing the
authentication token with permissions to search and read packages from
the NuGet feed

---------

Co-authored-by: freddydk <freddydk@users.noreply.github.com>
This commit is contained in:
Freddy Kristiansen 2024-09-24 09:21:27 +02:00 коммит произвёл GitHub
Родитель 7b377a3cc1
Коммит 8d7e66f44b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
12 изменённых файлов: 136 добавлений и 123 удалений

Просмотреть файл

@ -657,6 +657,7 @@ function ReadSettings {
"defaultIndexMD" = "## Reference documentation\n\nThis is the generated reference documentation for [{REPOSITORY}](https://github.com/{REPOSITORY}).\n\nYou can use the navigation bar at the top and the table of contents to the left to navigate your documentation.\n\nYou can change this content by creating/editing the **{INDEXTEMPLATERELATIVEPATH}** file in your repository or use the alDoc:defaultIndexMD setting in your repository settings file (.github/AL-Go-Settings.json)\n\n{RELEASENOTES}"
"defaultReleaseMD" = "## Release reference documentation\n\nThis is the generated reference documentation for [{REPOSITORY}](https://github.com/{REPOSITORY}).\n\nYou can use the navigation bar at the top and the table of contents to the left to navigate your documentation.\n\nYou can change this content by creating/editing the **{INDEXTEMPLATERELATIVEPATH}** file in your repository or use the alDoc:defaultReleaseMD setting in your repository settings file (.github/AL-Go-Settings.json)\n\n{RELEASENOTES}"
}
"trustMicrosoftNuGetFeeds" = $true
}
# Read settings from files and merge them into the settings object

Просмотреть файл

@ -1,4 +1,4 @@
Param(
Param(
[Parameter(HelpMessage = "The GitHub actor running the action", Mandatory = $false)]
[string] $actor,
[Parameter(HelpMessage = "The GitHub token running the action", Mandatory = $false)]
@ -189,7 +189,6 @@ foreach ($thisProject in $projectList) {
"RepoSettings" = $settings
"ProjectSettings" = $projectSettings
}
#Calculate the folders per artifact type
#Calculate the folders per artifact type
'Apps', 'TestApps', 'Dependencies' | ForEach-Object {
@ -226,9 +225,24 @@ foreach ($thisProject in $projectList) {
Write-Host "Calling custom script: $customScript"
. $customScript -parameters $parameters
}
elseif ($deliveryTarget -eq "GitHubPackages") {
$githubPackagesCredential = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($secrets.githubPackagesContext)) | ConvertFrom-Json
'Apps' | ForEach-Object {
elseif ($deliveryTarget -eq 'GitHubPackages' -or $deliveryTarget -eq 'NuGet') {
$preReleaseTag = ''
try {
$nuGetAccount = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($secrets."$($deliveryTarget)Context")) | ConvertFrom-Json | ConvertTo-HashTable
if ($deliveryTarget -eq 'NuGet' -and $type -eq 'CD') {
# When doing continuous delivery to NuGet, we always use the preview tag
# When doing a release, we do not add a preview tag
$preReleaseTag = 'preview'
}
$nuGetServerUrl = $nuGetAccount.ServerUrl
Write-Host $nuGetAccount.ServerUrl
$nuGetToken = $nuGetAccount.Token
Write-Host "$($deliveryTarget)Context secret OK"
}
catch {
throw "$($deliveryTarget)Context secret is malformed. Needs to be formatted as Json, containing serverUrl and token as a minimum."
}
'Apps','TestApps' | ForEach-Object {
$folder = @(Get-ChildItem -Path (Join-Path $artifactsFolder "$project-$refname-$($_)-*.*.*.*") | Where-Object { $_.PSIsContainer })
if ($folder.Count -gt 1) {
$folder | Out-Host
@ -237,93 +251,16 @@ foreach ($thisProject in $projectList) {
elseif ($folder.Count -eq 1) {
Get-Item -Path (Join-Path $folder[0] "*.app") | ForEach-Object {
$parameters = @{
"gitHubRepository" = "$ENV:GITHUB_SERVER_URL/$ENV:GITHUB_REPOSITORY"
"includeNuGetDependencies" = $true
"dependencyIdTemplate" = "AL-Go-{id}"
"packageId" = "AL-Go-{id}"
"gitHubRepository" = "$ENV:GITHUB_SERVER_URL/$ENV:GITHUB_REPOSITORY"
"preReleaseTag" = $preReleaseTag
"appFile" = $_.FullName
}
$parameters.appFiles = $_.FullName
$package = New-BcNuGetPackage @parameters
Push-BcNuGetPackage -nuGetServerUrl $gitHubPackagesCredential.serverUrl -nuGetToken $gitHubPackagesCredential.token -bcNuGetPackage $package
Push-BcNuGetPackage -nuGetServerUrl $nuGetServerUrl -nuGetToken $nuGetToken -bcNuGetPackage $package
}
}
}
}
elseif ($deliveryTarget -eq "NuGet") {
try {
$nuGetAccount = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($secrets.nuGetContext)) | ConvertFrom-Json | ConvertTo-HashTable
$nuGetServerUrl = $nuGetAccount.ServerUrl
$nuGetToken = $nuGetAccount.Token
Write-Host "NuGetContext secret OK"
}
catch {
throw "NuGetContext secret is malformed. Needs to be formatted as Json, containing serverUrl and token as a minimum."
}
$appsfolder = @(Get-ChildItem -Path (Join-Path $artifactsFolder "$project-$refname-Apps-*.*.*.*") | Where-Object { $_.PSIsContainer })
if ($appsFolder.Count -eq 0) {
throw "Internal error - unable to locate apps folder"
}
elseif ($appsFolder.Count -gt 1) {
$appsFolder | Out-Host
throw "Internal error - multiple apps folders located"
}
$testAppsFolder = @(Get-ChildItem -Path (Join-Path $artifactsFolder "$project-$refname-TestApps-*.*.*.*") | Where-Object { $_.PSIsContainer })
if ($testAppsFolder.Count -gt 1) {
$testAppsFolder | Out-Host
throw "Internal error - multiple testApps folders located"
}
$dependenciesFolder = @(Get-ChildItem -Path (Join-Path $artifactsFolder "$project-$refname-Dependencies-*.*.*.*") | Where-Object { $_.PSIsContainer })
if ($dependenciesFolder.Count -gt 1) {
$dependenciesFolder | Out-Host
throw "Internal error - multiple dependencies folders located"
}
$parameters = @{
"gitHubRepository" = "$ENV:GITHUB_SERVER_URL/$ENV:GITHUB_REPOSITORY"
}
$parameters.appFiles = @(Get-Item -Path (Join-Path $appsFolder[0] "*.app") | ForEach-Object { $_.FullName })
if ($testAppsFolder.Count -gt 0) {
$parameters.testAppFiles = @(Get-Item -Path (Join-Path $testAppsFolder[0] "*.app") | ForEach-Object { $_.FullName })
}
if ($dependenciesFolder.Count -gt 0) {
$parameters.dependencyAppFiles = @(Get-Item -Path (Join-Path $dependenciesFolder[0] "*.app") | ForEach-Object { $_.FullName })
}
if ($nuGetAccount.Keys -contains 'PackageName') {
$parameters.packageId = $nuGetAccount.PackageName.replace('{project}', $projectName).replace('{owner}', $ENV:GITHUB_REPOSITORY_OWNER).replace('{repo}', $settings.repoName)
}
else {
if ($thisProject -and ($thisProject -eq '.')) {
$parameters.packageId = "$($ENV:GITHUB_REPOSITORY_OWNER)-$($settings.repoName)"
}
else {
$parameters.packageId = "$($ENV:GITHUB_REPOSITORY_OWNER)-$($settings.repoName)-$ProjectName"
}
}
if ($type -eq 'CD') {
$parameters.packageId += "-preview"
}
$parameters.packageVersion = [System.Version]$appsFolder[0].Name.SubString($appsFolder[0].Name.IndexOf("-Apps-") + 6)
if ($nuGetAccount.Keys -contains 'PackageTitle') {
$parameters.packageTitle = $nuGetAccount.PackageTitle
}
else {
$parameters.packageTitle = $parameters.packageId
}
if ($nuGetAccount.Keys -contains 'PackageDescription') {
$parameters.packageDescription = $nuGetAccount.PackageDescription
}
else {
$parameters.packageDescription = $parameters.packageTitle
}
if ($nuGetAccount.Keys -contains 'PackageAuthors') {
$parameters.packageAuthors = $nuGetAccount.PackageAuthors
}
else {
$parameters.packageAuthors = $actor
}
$package = New-BcNuGetPackage @parameters
Push-BcNuGetPackage -nuGetServerUrl $nuGetServerUrl -nuGetToken $nuGetToken -bcNuGetPackage $package
}
elseif ($deliveryTarget -eq "Storage") {
InstallAzModuleIfNeeded -name 'Az.Storage'
try {
@ -457,9 +394,9 @@ foreach ($thisProject in $projectList) {
}
$depfolder = $depfolder[0].FullName
$libraryAppFiles += @(Get-ChildItem -path $depFolder | Where-Object {
$name = $_.name
$appSourceIncludeDependencies | Where-Object { $name -like $_ }
} | ForEach-Object { $_.FullName })
$name = $_.name
$appSourceIncludeDependencies | Where-Object { $name -like $_ }
} | ForEach-Object { $_.FullName })
}
Write-Host "Main App File:"

Просмотреть файл

@ -5,6 +5,16 @@
[bool] $checkContextSecrets
)
function ContinuousDelivery([string] $deliveryTarget) {
$settingsName = "DeliverTo$deliveryTarget"
if ($settings.Contains($settingsName) -and $settings."$settingsName".Contains('ContinuousDelivery')) {
return $settings."$settingsName".ContinuousDelivery
}
else {
return $true
}
}
function IncludeBranch([string] $deliveryTarget) {
$settingsName = "DeliverTo$deliveryTarget"
if ($settings.Contains($settingsName) -and $settings."$settingsName".Contains('Branches')) {
@ -26,7 +36,7 @@ function IncludeDeliveryTarget([string] $deliveryTarget) {
Write-Host "- Secret '$contextName' not found"
return $false
}
return (IncludeBranch -deliveryTarget $deliveryTarget)
return (IncludeBranch -deliveryTarget $deliveryTarget) -and (ContinuousDelivery -deliveryTarget $deliveryTarget)
}
. (Join-Path -Path $PSScriptRoot -ChildPath "..\AL-Go-Helper.ps1" -Resolve)

Просмотреть файл

@ -11,7 +11,7 @@ The action constructs arrays of paths to .app files, that are dependencies of th
| Name | Description |
| :-- | :-- |
| Settings | env.Settings must be set by a prior call to the ReadSettings Action |
| Secrets | env.Secrets must be read by a prior call to the ReadSecrets Action with appDependencyProbingPathsSecrets in getSecrets |
| Secrets | env.Secrets must be read by a prior call to the ReadSecrets Action with appDependencySecrets in getSecrets |
### Parameters

Просмотреть файл

@ -2,7 +2,7 @@
Read secrets from GitHub secrets or Azure Keyvault for AL-Go workflows
The secrets read and added to the output are the secrets specified in the getSecrets parameter
Additionally, the secrets specified by the authToken secret in AppDependencyProbingPaths are read if appDependencyProbingPathsSecrets is specified in getSecrets
Additionally, the secrets specified by the authTokenSecret in AppDependencyProbingPaths and TrustedNuGetFeeds are read if appDependencySecrets is specified in getSecrets
All secrets included in the Secrets output are Base64 encoded to avoid issues with national characters
Secrets, which name is preceded by an asterisk (\*) are encrypted and Base64 encoded
@ -20,7 +20,7 @@ Secrets, which name is preceded by an asterisk (\*) are encrypted and Base64 enc
| :-- | :-: | :-- | :-- |
| shell | | The shell (powershell or pwsh) in which the PowerShell script in this action should run | powershell |
| gitHubSecrets | Yes | GitHub secrets in a json structure | |
| getSecrets | Yes | Comma-separated list of secrets to get (add appDependencyProbingPathsSecrets to request secrets needed for resolving dependencies in AppDependencyProbingPaths, add TokenForPush in order to request a token to use for pull requests and commits). Secrets preceded by an asterisk are returned encrypted | |
| getSecrets | Yes | Comma-separated list of secrets to get (add appDependencySecrets to request secrets needed for resolving dependencies in AppDependencyProbingPaths and TrustedNuGetFeeds, add TokenForPush in order to request a token to use for pull requests and commits). Secrets preceded by an asterisk are returned encrypted | |
| useGhTokenWorkflowForPush | false | Determines whether you want to use the GhTokenWorkflow secret for TokenForPush | false |
## OUTPUT

Просмотреть файл

@ -27,7 +27,7 @@ try {
$outSecrets = [ordered]@{}
$settings = $env:Settings | ConvertFrom-Json | ConvertTo-HashTable
$keyVaultCredentials = GetKeyVaultCredentials
$getAppDependencyProbingPathsSecrets = $false
$getAppDependencySecrets = $false
$getTokenForPush = $false
[System.Collections.ArrayList]$secretsCollection = @()
foreach($secret in ($getSecrets.Split(',') | Select-Object -Unique)) {
@ -38,8 +38,8 @@ try {
$secret = 'ghTokenWorkflow'
}
$secretNameProperty = "$($secret.TrimStart('*'))SecretName"
if ($secret -eq 'AppDependencyProbingPathsSecrets') {
$getAppDependencyProbingPathsSecrets = $true
if ($secret -eq 'AppDependencySecrets') {
$getAppDependencySecrets = $true
}
else {
$secretName = $secret
@ -61,12 +61,19 @@ try {
}
}
# Loop through appDependencyProbingPaths and add secrets to the collection of secrets to get
if ($getAppDependencyProbingPathsSecrets -and $settings.Keys -contains 'appDependencyProbingPaths') {
foreach($appDependencyProbingPath in $settings.appDependencyProbingPaths) {
if ($appDependencyProbingPath.PsObject.Properties.name -eq "AuthTokenSecret") {
if ($secretsCollection -notcontains $appDependencyProbingPath.authTokenSecret) {
$secretsCollection += $appDependencyProbingPath.authTokenSecret
if ($getAppDependencySecrets) {
# Loop through appDependencyProbingPaths and trustedNuGetFeeds and add secrets to the collection of secrets to get
$settingsCollection = @()
if ($settings.Keys -contains 'appDependencyProbingPaths') {
$settingsCollection += $settings.appDependencyProbingPaths
}
if ($settings.Keys -contains 'trustedNuGetFeeds') {
$settingsCollection += $settings.trustedNuGetFeeds
}
foreach($settingsItem in $settingsCollection) {
if ($settingsItem.PsObject.Properties.name -eq "AuthTokenSecret") {
if ($secretsCollection -notcontains $settingsItem.authTokenSecret) {
$secretsCollection += $settingsItem.authTokenSecret
}
}
}

Просмотреть файл

@ -118,6 +118,38 @@ try {
exit
}
if ($bcContainerHelperConfig.ContainsKey('TrustedNuGetFeeds')) {
Write-Host "Reading TrustedNuGetFeeds"
foreach($trustedNuGetFeed in $bcContainerHelperConfig.TrustedNuGetFeeds) {
if ($trustedNuGetFeed.PSObject.Properties.Name -eq 'Token') {
if ($trustedNuGetFeed.Token -ne '') {
OutputWarning -message "Auth token for NuGet feed is defined in settings. This is not recommended. Use a secret instead and specify the secret name in the AuthTokenSecret property"
}
}
else {
$trustedNuGetFeed | Add-Member -MemberType NoteProperty -Name 'Token' -Value ''
}
if ($trustedNuGetFeed.PSObject.Properties.Name -eq 'AuthTokenSecret' -and $trustedNuGetFeed.AuthTokenSecret) {
$authTokenSecret = $trustedNuGetFeed.AuthTokenSecret
if ($secrets.Keys -notcontains $authTokenSecret) {
OutputWarning -message "Secret $authTokenSecret needed for trusted NuGetFeeds cannot be found"
}
else {
$trustedNuGetFeed.Token = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($secrets."$authTokenSecret"))
}
}
}
}
else {
$bcContainerHelperConfig.TrustedNuGetFeeds = @()
}
if ($settings.trustMicrosoftNuGetFeeds) {
$bcContainerHelperConfig.TrustedNuGetFeeds += @([PSCustomObject]@{
"url" = "https://dynamicssmb2.pkgs.visualstudio.com/DynamicsBCPublicFeeds/_packaging/AppSourceSymbols/nuget/v3/index.json"
"token" = ''
})
}
$installApps = $settings.installApps
$installTestApps = $settings.installTestApps
@ -276,8 +308,13 @@ try {
}
}
if ($gitHubPackagesContext -and ($runAlPipelineParams.Keys -notcontains 'InstallMissingDependencies')) {
$gitHubPackagesCredential = $gitHubPackagesContext | ConvertFrom-Json
if ((($bcContainerHelperConfig.ContainsKey('TrustedNuGetFeeds') -and ($bcContainerHelperConfig.TrustedNuGetFeeds.Count -gt 0)) -or ($gitHubPackagesContext)) -and ($runAlPipelineParams.Keys -notcontains 'InstallMissingDependencies')) {
if ($githubPackagesContext) {
$gitHubPackagesCredential = $gitHubPackagesContext | ConvertFrom-Json
}
else {
$gitHubPackagesCredential = [PSCustomObject]@{ "serverUrl" = ''; "token" = '' }
}
$runAlPipelineParams += @{
"InstallMissingDependencies" = {
Param([Hashtable]$parameters)
@ -289,7 +326,7 @@ try {
$publishParams = @{
"nuGetServerUrl" = $gitHubPackagesCredential.serverUrl
"nuGetToken" = $gitHubPackagesCredential.token
"packageName" = "AL-Go-$appId"
"packageName" = $appId
"version" = $version
}
if ($parameters.ContainsKey('CopyInstalledAppsToFolder')) {
@ -298,12 +335,11 @@ try {
}
}
if ($parameters.ContainsKey('containerName')) {
Publish-BcNuGetPackageToContainer -containerName $parameters.containerName -tenant $parameters.tenant -skipVerification @publishParams
Publish-BcNuGetPackageToContainer -containerName $parameters.containerName -tenant $parameters.tenant -skipVerification -appSymbolsFolder $parameters.appSymbolsFolder @publishParams -ErrorAction SilentlyContinue
}
else {
Copy-BcNuGetPackageToFolder -appSymbolsFolder $parameters.appSymbolsFolder @publishParams
Download-BcNuGetPackageToFolder -folder $parameters.appSymbolsFolder @publishParams | Out-Null
}
}
}
}

Просмотреть файл

@ -2,6 +2,20 @@
- Issue 1184 Publish to Environment fails on 'Permission Denied'
### New Settings
- `deliverTo<deliverytarget>` now has an additional property called `ContinuousDelivery`, indicating whether or not to run continuous delivery to this deliveryTarget. Default is true.
- `trustMicrosoftNuGetFeeds` Unless this setting is set to false, AL-Go for GitHub will trust the NuGet feeds provided by Microsoft. The feeds provided by Microsoft contains all Microsoft apps, all Microsoft symbols and symbols for all AppSource apps.
- `trustedNuGetFeeds` - can be an array of NuGet feed specifications, which AL-Go for GitHub will use for dependency resolution. Every feed specification must include a URL property and can optionally include a few other properties:
- url - The URL of the feed (examples: https://pkgs.dev.azure.com/myorg/apps/\_packaging/myrepo/nuget/v3/index.json or https://nuget.pkg.github.com/mygithuborg/index.json").
- patterns - AL-Go for GitHub will only trust packages, where the ID matches this pattern. Default is all packages (\*).
- fingerprints - If specified, AL-Go for GitHub will only trust packages signed with a certificate with a fingerprint matching one of the fingerprints in this array.
- authTokenSecret - If the NuGet feed specified by URL is private, the authTokenSecret must be the name of a secret containing the authentication token with permissions to search and read packages from the NuGet feed.
### Support for delivering to GitHub Packages and NuGet
With this release the implementation for delivering to NuGet packages (by adding the NuGetContext secret), is similar to the functionality behind delivering to GitHub packages and the implementation is no longer in preview.
### Allow GitHubRunner and GitHubRunnerShell as project settings
Previously, AL-Go required the GitHubRunner and GitHubRunnerShell settings to be set on repository level. This has now been changed such that they can be set on project level.

Просмотреть файл

@ -77,13 +77,13 @@ Whether you use a managed identity or an app registration for authentication, yo
Using a federated credential, you need to register your GitHub repository in your managed identity under settings -> federated credentials or in the app registration under Certificates & Secrets. This registration will allow AL-Go for GitHub running in this repository to authenticate without the Client Secret stored. You still need to create a secret containing the clientId and the tenantId. The way this works is that AL-Go for GitHub will request an ID_TOKEN from GitHub as a proof of authenticity and use this when authenticating. This way, only workflows running in the specified branch/environment in GitHub will be able to authenticate.
Example: `{"keyVaultName":"MyKeyVault","clientId":"ed79570c-0384-4826-8099-bf0577af6667","tenantId":"c645f7e7-0613-4b82-88ca-71f3dbb40045"}`
Example: `{"keyVaultName":"MyKeyVault","clientId":"<clientId>","tenantId":"<tenantId>"}`
#### ClientSecret
ClientSecret can only be used using an app registration. Under Certificates & Secrets in the app registration, you need to create a Client Secret, which you can specify in the Azure_Credentials secret in AL-Go for GitHub. With the ClientId and ClientSecret, anybody can authenticate and perform actions as the connected user inside Business Central.
Example: `{"keyVaultName":"MyKeyVault","clientId":"d48b773f-2c26-4394-8bd2-c5b64e0cae32","clientSecret":"OPXxxxxxxxxxxxxxxxxxxxxxxabge","tenantId":"c645f7e7-0613-4b82-88ca-71f3dbb40045"}`
Example: `{"keyVaultName":"MyKeyVault","clientId":"<clientId>","clientSecret":"<clientSecret>","tenantId":"<tenantId>"}`
With this setup, you can create a setting called `keyVaultCodesignCertificateName` containing the name of the imported certificate in your Key Vault in order for AL-Go for GitHub to sign your apps.
@ -101,7 +101,7 @@ Specifying a RefreshToken allows AL-Go for GitHub to get access to impersonate t
Providing an AuthContext secret with a refreshtoken typically allows you to get access for 90 days. After the 90 days, you need to refresh the AuthContext secret with a new refreshToken. Note that anybody with the refreshToken can get access to call the API on behalf of the user, it doesn't have to be inside a workflow/pipeline.
Example: `{"tenantId":"d630ce39-5a0c-41ec-bf0d-6758ad558f0c","scopes":"https://api.businesscentral.dynamics.com/","RefreshToken":"0.AUUAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_s6Eo4YOI","clientId":"1950a258-227b-4e31-a9cf-717495945fc2"}`
Example: `{"tenantId":"<tenantId>","scopes":"https://api.businesscentral.dynamics.com/","RefreshToken":"<refreshToken>","clientId":"<clientId>"}`
### App Registration (Service to service authentication)
@ -117,7 +117,7 @@ Example:`{"tenantId":"d630ce39-5a0c-41ec-bf0d-6758ad558f0c","scopes":"https://ap
Under Certificates & Secrets in the app registration, you can create a Client Secret, which you can specify in the AuthContext secret in AL-Go for GitHub. With the ClientId and ClientSecret, anybody can authenticate and perform actions as the connected user inside Business Central.
Example: `{"tenantId":"d630ce39-5a0c-41ec-bf0d-6758ad558f0c","scopes":"https://api.businesscentral.dynamics.com/","clientId":"d48b773f-2c26-4394-8bd2-c5b64e0cae32","clientSecret":"OPXxxxxxxxxxxxxxxxxxxxxxxabge"}`
Example: `{"tenantId":"<tenantId>","scopes":"https://api.businesscentral.dynamics.com/","clientId":"<clientId>","clientSecret":"<clientSecret>"}`
## <a id="AppSourceContext"></a>**AppSourceContext** -> Deliver to AppSource
@ -135,13 +135,13 @@ In order to use an app registration for publishing apps to AppSource, you need t
Using a federated credential, you need to register your GitHub repository in the app registration under Certificates & Secrets. This registration will allow AL-Go for GitHub running in this repository to authenticate without the Client Secret stored. You still need to create a secret containing this information. The way this works is that AL-Go for GitHub will request an ID_TOKEN from GitHub as a proof of authenticity and use this when authenticating. This way, only workflows running in the specified branch/environment in GitHub will be able to authenticate.
Example:`{"clientId":"d48b773f-2c26-4394-8bd2-c5b64e0cae32","tenantId":"c645f7e7-0613-4b82-88ca-71f3dbb40045","scopes":"https://api.partner.microsoft.com/.default"}`
Example:`{"clientId":"<clientId>","tenantId":"<tenantId>","scopes":"https://api.partner.microsoft.com/.default"}`
#### Client Secret
Under Certificates & Secrets in the app registration, you can create a Client Secret, which you can specify in the AuthContext secret in AL-Go for GitHub. Note that who ever has access to the clientId and clientSecret can publish apps on AppSource on your behalf.
Example: `{"tenantId":"c645f7e7-0613-4b82-88ca-71f3dbb40045","scopes":"https://api.partner.microsoft.com/.default","clientId":"d48b773f-2c26-4394-8bd2-c5b64e0cae32","clientSecret":"OPXxxxxxxxxxxxxxxxxxxxxxxabge"}`
Example: `{"tenantId":"c645f7e7-0613-4b82-88ca-71f3dbb40045","scopes":"https://api.partner.microsoft.com/.default","clientId":"<clientId>","clientSecret":"<clientSecret>"}`
## <a id="StorageContext"></a>**StorageContext** -> Deliver to storage
@ -153,34 +153,40 @@ In AL-Go for GitHub, the Storage Context can be specified in 5 different ways, 5
As a storage account is an Azure resource, we can use managed identities. Managed identities are like virtual users in Azure, using federated credentials for authentication. Using a federated credential, you need to register your GitHub repository in the managed identity under Settings -> Federated Credentials. The way this works is that AL-Go for GitHub will request an ID_TOKEN from GitHub as a proof of authenticity and use this when authenticating. This way, only workflows running in the specified branch/environment in GitHub will be able to authenticate.
Example: `{"storageAccountName":"MyStorageName","clientId":"08b6d80c-68cf-48f9-a5ff-b054326e2ec3","tenantId":"c645f7e7-0613-4b82-88ca-71f3dbb40045","containerName":"{project}","blobName":"{version}/{project}-{type}.zip"}`
Example: `{"storageAccountName":"MyStorageName","clientId":"<clientId>","tenantId":"<tenantId>","containerName":"{project}","blobName":"{version}/{project}-{type}.zip"}`
### App Registration/Federated credential
An app registration with federated credential is harder to setup than a managed identity, but just as secure. The mechanism is the same for obtaining an ID_TOKEN and providing this as proof of authenticity towards the app registration.
Example: `{"storageAccountName":"MyStorageName","clientId":"d48b773f-2c26-4394-8bd2-c5b64e0cae32","tenantId":"c645f7e7-0613-4b82-88ca-71f3dbb40045","containerName":"{project}","blobName":"{version}/{project}-{type}.zip"}`
Example: `{"storageAccountName":"MyStorageName","clientId":"<clientId>","tenantId":"<tenantId>","containerName":"{project}","blobName":"{version}/{project}-{type}.zip"}`
### App Registration/Client Secret
An app registration with a client Secret is less secure than using federated credentials. Who ever has access to the clientSecret has access to everything the app registration has access to, until you recycle the client Secret.
Example: `{"storageAccountName":"MyStorageName","clientId":"d48b773f-2c26-4394-8bd2-c5b64e0cae32","clientSecret":"OPXxxxxxxxxxxxxxxxxxxxxxxabge","tenantId":"c645f7e7-0613-4b82-88ca-71f3dbb40045","containerName":"{project}","blobName":"{version}/{project}-{type}.zip"}`
Example: `{"storageAccountName":"MyStorageName","clientId":"<clientId>","clientSecret":"<clientSecret>","tenantId":"<tenantId>","containerName":"{project}","blobName":"{version}/{project}-{type}.zip"}`
### storageAccountName/sastoken
A sas token for a storage account can be setup to function in a limited timeframe, giving access to perform a certain number of tasks on the storage account. Who ever has access to the sastoken can perform these tasks on the storage account until it expires or you recycle the storage account key used to create the sastoken.
Example: `{"storageAccountName":"MyStorageName","sastoken":"sv=2022-11-02&ss=b&srt=sco&sp=rwdlaciytf&se=2024-08-06T20:22:08Z&st=2024-04-06T12:22:08Z&spr=https&sig=IZyIf5xxxxxxxxxxxxxxxxxxxxxtq7tj6b5I%3D","containerName":"{project}","blobName":"{version}/{project}-{type}.zip"}`
Example: `{"storageAccountName":"MyStorageName","sastoken":"sv=2022-11-02&ss=b&srt=sco&sp=rwdlaciytf&se=2024-08-06T20:22:08Z&st=2024-04-06T12:22:08Z&spr=https&sig=<signature>","containerName":"{project}","blobName":"{version}/{project}-{type}.zip"}`
### storageAccountName/storageAccountKey
Using storageAccount Name and Key is by far the most unsecure way of authenticating to an Azure Storage Account. If ever compromised, people can do anything with these credentials, until the storageAccount key is cycled.
Example: `{"storageAccountName":"MyStorageName","storageAccountKey":"JHFZErCyfQ8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxStj7AHXQ==","containerName":"{project}","blobName":"{version}/{project}-{type}.zip"} `
Example: `{"storageAccountName":"MyStorageName","storageAccountKey":"<storageAccountKey>","containerName":"{project}","blobName":"{version}/{project}-{type}.zip"} `
## <a id="GitHubPackagesContext"></a>**GitHubPackagesContext** -> Deliver to GitHub Packages
If you create a secret called GitHubPackagesContext, then AL-Go for GitHub will automagically deliver apps to this NuGet feed after every successful build. AL-Go for GitHub will also use this NuGet feed for dependency resolution when building apps, giving you automatic dependency resolution within all your apps.
If you create a secret called GitHubPackagesContext, then AL-Go for GitHub will automagically deliver apps to this NuGet feed after every successful build. AL-Go for GitHub will also use this NuGet feed for dependency resolution when building apps, giving you automatic dependency resolution within all your repositories sharing this secret.
Example: `{"token":"ghp_NDdI2ExxxxxxxxxxxxxxxxxAYQh","serverUrl":"https://nuget.pkg.github.com/mygithuborg/index.json"}`
Example: `{"token":"<gitHubToken>","serverUrl":"https://nuget.pkg.github.com/mygithuborg/index.json"}`
## <a id="NuGetContext"></a>**NuGetContext** -> Deliver to NuGet
If you create a secret called NuGetContext, then AL-Go for GitHub will automagically deliver apps to this NuGet feed after every successful build. AL-Go for GitHub will NOT use this NuGet feed for dependency resolution when building apps. If you want to use this feed for dependency resolution as well, you need to add this to the [trustedNuGetFeeds](https://aka.ms/algosettings#trustedNuGetFeeds) setting.
Example: `{"token":"<nuGetToken>","serverUrl":"https://pkgs.dev.azure.com/myorg/apps/_packaging/myrepo/nuget/v3/index.json"}`

Просмотреть файл

@ -116,6 +116,8 @@ The repository settings are only read from the repository settings file (.github
| <a id="enableTaskScheduler"></a>enableTaskScheduler | Setting enableTaskScheduler to true in your project setting file, causes the build container to be created with the Task Scheduler running. | false |
| <a id="useCompilerFolder"></a>useCompilerFolder | Setting useCompilerFolder to true causes your pipelines to use containerless compiling. Unless you also set **doNotPublishApps** to true, setting useCompilerFolder to true won't give you any performance advantage, since AL-Go for GitHub will still need to create a container in order to publish and test the apps. In the future, publishing and testing will be split from building and there will be other options for getting an instance of Business Central for publishing and testing. **Note** when using UseCompilerFolder you need to sign apps using the new signing mechanism described [here](../Scenarios/Codesigning.md). | false |
| <a id="excludeEnvironments"></a>excludeEnvironments | excludeEnvironments can be an array of GitHub Environments, which should be excluded from the list of environments considered for deployment. github-pages is automatically added to this array and cannot be used as environment for deployment of AL-Go for GitHub projects. | \[ \] |
| <a id="trustMicrosoftNuGetFeeds"></a>trustMicrosoftNuGetFeeds | Unless this setting is set to false, AL-Go for GitHub will trust the NuGet feeds provided by Microsoft. The feeds provided by Microsoft contains all Microsoft apps, all Microsoft symbols and symbols for all AppSource apps. | true |
| <a id="trustedNuGetFeeds"></a>trustedNuGetFeeds | trustedNuGetFeeds can be an array of NuGet feed specifications, which AL-Go for GitHub will use for dependency resolution. Every feed specification must include a URL property and can optionally include a few other properties:<br />**url** = The URL of the feed (examples: https://pkgs.dev.azure.com/myorg/apps/\_packaging/myrepo/nuget/v3/index.json or https://nuget.pkg.github.com/mygithuborg/index.json").<br />**authTokenSecret** = If the NuGet feed specified by URL is private, the authTokenSecret must be the name of a secret containing the authentication token with permissions to search and read packages from the NuGet feed.<br />**patterns** = AL-Go for GitHub will only trust packages, where the ID matches this pattern. Default is all packages (\*).<br />**fingerprints** = If specified, AL-Go for GitHub will only trust packages signed with a certificate with a fingerprint matching one of the fingerprints in this array. | \[ \] |
## AppSource specific advanced settings

Просмотреть файл

@ -106,7 +106,7 @@ jobs:
with:
shell: ${{ inputs.shell }}
gitHubSecrets: ${{ toJson(secrets) }}
getSecrets: '${{ inputs.secrets }},appDependencyProbingPathsSecrets,AZURE_CREDENTIALS'
getSecrets: '${{ inputs.secrets }},appDependencySecrets,AZURE_CREDENTIALS'
- name: Determine ArtifactUrl
uses: microsoft/AL-Go-Actions/DetermineArtifactUrl@main

Просмотреть файл

@ -106,7 +106,7 @@ jobs:
with:
shell: ${{ inputs.shell }}
gitHubSecrets: ${{ toJson(secrets) }}
getSecrets: '${{ inputs.secrets }},appDependencyProbingPathsSecrets,AZURE_CREDENTIALS'
getSecrets: '${{ inputs.secrets }},appDependencySecrets,AZURE_CREDENTIALS'
- name: Determine ArtifactUrl
uses: microsoft/AL-Go-Actions/DetermineArtifactUrl@main