AzureDevOpsDscNative.psd1
|
@{ RootModule = 'AzureDevOpsDscNative.psm1' # Version number of this module. # # This value is a fallback for local and CI builds only. Released versions are # driven by the git tag: the publish workflow sets $env:ModuleVersion from the # tag, and the build stamps that value into the packaged manifest instead of this # one. Do not hand-edit this to cut a release - push a vX.Y.Z tag. moduleVersion = '1.3.0' # ID used to uniquely identify this module GUID = 'e7eb078e-5e97-42be-ae8f-decb140fc38e' # Author of this module Author = 'ZanattaMichael' # Company or vendor of this module CompanyName = 'ZanattaMichael' # Copyright statement for this module Copyright = 'Copyright the DSC Community contributors and ZanattaMichael. All rights reserved.' # Description of the functionality provided by this module Description = 'A fork of the DSC Community AzureDevOpsDsc module with native DSC v3 support: every resource is discoverable and invokable by dsc.exe via the Microsoft.Adapter/PowerShell adapter, using generated adapted resource manifests, without requiring a wrapper resource.' # Minimum version of the Windows PowerShell engine required by this module PowerShellVersion = '7.0' # Minimum version of the common language runtime (CLR) required by this module CLRVersion = '4.0' # Functions to export from this module #FunctionsToExport = @() # Cmdlets to export from this module #CmdletsToExport = @() # Variables to export from this module VariablesToExport = @() # Aliases to export from this module AliasesToExport = @() # Import all the 'DSCClassResource', modules as part of this module NestedModules = @() DscResourcesToExport = @('AzDoGroupPermission','AzDoOrganizationGroup','AzDoProject','AzDoProjectServices','AzDoProjectGroup','AzDoGroupMember','AzDoGitRepository','AzDoGitPermission','AzDoAreaPermission','AzDoIterationPermission','AzDoWIPTags','AzDoAreaNodes','AzDoIterationNodes','AzDoBranchPolicy','AzDoVariableGroup','AzDoServiceConnection','AzDoPipelineEnvironment','AzDoAgentPool','AzDoAgentQueue','AzDoTeam','AzDoTeamMember','AzDoPipeline','AzDoPipelinePermission','AzDoEnvironmentApproval','AzDoVariableGroupPermission','AzDoServiceConnectionPermission','AzDoAgentPoolPermission','AzDoSecurityNamespacePermission','AzDoArtifactFeed','AzDoArtifactFeedPermission','AzDoDeploymentGroup','AzDoTaskGroup','AzDoOrganizationSettings','AzDoExtension','AzDoAuditStream','AzDoProjectPermission','AzDoEnvironmentPermission','AzDoWiki','AzDoNotificationSubscription','AzDoRepositorySettings','AzDoCheckConfiguration','AzDoTeamSettings','AzDoArtifactFeedSettings','AzDoArtifactFeedView','AzDoProcess','AzDoProcessPermission','AzDoUserEntitlement','AzDoServiceHook','AzDoPipelineSettings','AzDoQueryFolder','AzDoWorkItemQuery','AzDoQueryPermission','AzDoWIPTagHygiene','AzDoSecureFile','AzDoSecureFilePermission','AzDoPipelineFolder','AzDoPipelineFolderPermission','AzDoGroupEntitlement','AzDoServicePrincipalEntitlement','AzDoPicklist','AzDoProcessWorkItemType','AzDoProcessField','AzDoProcessState','AzDoProcessRule','AzDoProcessBehavior','AzDoPipelineAuthorization','AzDoEnvironmentKubernetesResource','AzDoEnvironmentVMResource','AzDoDeploymentGroupTarget','AzDoReleaseFolder','AzDoReleaseFolderPermission','AzDoReleaseDefinitionPermission','AzDoTestVariable','AzDoTestConfiguration','AzDoTestPlan','AzDoTestSuite','AzDoBuildRetentionSettings','AzDoWikiPage','AzDoTaggingPermission','AzDoAnalyticsPermission','AzDoAnalyticsViewsPermission','AzDoDashboard','AzDoOrganizationPermission','AzDoTaskGroupPermission') RequiredAssemblies = @() # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. PrivateData = @{ PSData = @{ # Set to a prerelease string value if the release should be a prerelease. Prerelease = '' # Tags applied to this module. These help with module discovery in online galleries. Tags = @('DesiredStateConfiguration', 'DSC', 'DSCResourceKit', 'DSCResource', 'DSCv3', 'AzureDevOps') # A URL to the license for this module. LicenseUri = 'https://github.com/ZanattaMichael/AzureDevOpsDsc/blob/main/LICENSE' # A URL to the main website for this project. ProjectUri = 'https://github.com/ZanattaMichael/AzureDevOpsDsc' # A URL to an icon representing this module. IconUri = 'https://dsccommunity.org/images/DSC_Logo_300p.png' # ReleaseNotes of this module. # Per-release notes are generated from the CHANGELOG's [Unreleased] section # at build time and attached to the GitHub Release. This link is the fallback # shown on the Gallery listing. ReleaseNotes = '## [1.3.0] - 2026-11-08 ### Security - Credential storage - `New-AzDoAuthenticationProvider` no longer leaves `ModuleSettings.clixml` and the cache directory with default permissions. A new private helper, `Protect-AzDoCachePath`, restricts everything the module writes under `AZDODSC_CACHE_DIRECTORY` to its owner: on Windows the ACL is replaced with an explicit, non-inherited DACL granting FullControl to the current user, SYSTEM and BUILTIN\Administrators only; on Linux and macOS files are set to mode 600 and directories to 700. `New-AzDoAuthenticationProvider`, `Export-CacheObject`, `Initialize-CacheObject` and `Save-IdentityDescriptorIndex` apply it to every directory they create and file they write, so the identity caches and `IdentityDescriptorIndex.clixml`, which decide which identity a permission grant resolves to, are covered as well. A permissions failure is a warning, never an error. - On Linux and macOS `Export-Clixml` stores a SecureString as hex-encoded UTF-16, so `ModuleSettings.clixml` holds the credential in a recoverable form. `New-AzDoAuthenticationProvider` now warns on those platforms that the file is protected only by the owner-only permissions it sets, that `AZDODSC_CACHE_DIRECTORY` must be a private path, and that DSC must run as the same account. `USAGE.md` and `CLAUDE.md` describe this. - `New-AzDoAuthenticationProvider` defaults to the `SecureStringPersonalAccessToken` parameter set. The plain-text `-PersonalAccessToken` and `-ClientSecret` parameters still work but warn that the secret lands in shell history, transcripts and process listings, and name the `-SecureStringPersonalAccessToken` / `-SecureStringClientSecret` alternative. Every example and the integration test framework use the SecureString parameters. - Transport - `Invoke-AzDevOpsApiRestMethod` refuses any request that is not https before it builds an Authorization header. The only exceptions are the two instance metadata endpoints that answer http only: IMDS (`169.254.169.254`) and the Azure Arc agent on `localhost`. `Test-AzDevOpsApiUri` accepts https only. - Azure Arc - `Get-AzManagedIdentityToken` validates both Azure Arc inputs before using them, as Microsoft''s reference implementations do. `IDENTITY_ENDPOINT` must be an absolute http/https URI on `localhost`, `127.0.0.1` or `::1`; the secret file path from the 401 challenge (`WWW-Authenticate: Basic realm=<path>`) must be a `.key` file directly inside the Arc tokens directory (`%ProgramData%\AzureConnectedMachineAgent\Tokens` on Windows, `/var/opt/azcmagent/tokens` on Linux). Anything else throws, naming the value, before a request is sent or a file is read. New private helpers `Test-AzDoArcSecretFilePath` and `Get-AzDoArcTokensDirectory`. - Token guard - `AuthenticationToken.TestCaller()` no longer carries the `Write-*` and `Out-File` checks, which could never fire (`TestCallStack` compares whole command names, and arguments are evaluated before a cmdlet is on the stack). The comments above it and above `ServicePrincipalToken.GetClientSecret()` now say what the remaining call-stack check is: a guard against accidental use of the plain token outside the module''s request path, not a security boundary. The allowed-callers behaviour is unchanged. - Secrets in logs and exports - `AzDevOpsDscResourceBase` gains `FormatPropertiesForLog()`, which renders current-state properties for verbose logging with secret properties (those named by `GetDscResourceSecretPropertyNames()`) shown as `<redacted>` and hashtable-valued properties shown as key names only. `AzDoVariableGroup`, `AzDoServiceConnection`, `AzDoAuditStream` and `AzDoServiceHook` log through it, so variable values, a service connection''s `serviceprincipalkey` and consumer credentials no longer reach DSC verbose logs. - `AzDoServiceConnection` declares `Authorization`, and `AzDoAuditStream` and `AzDoServiceHook` declare `ConsumerInputs`, as secret properties, so `Export()` redacts them through `Protect-AzDoExportedSecretProperty` instead of writing them out. - `AzDoVariableGroup` can create secret variables: `Variables` accepts `@{ NAME = @{ value = ''v''; isSecret = $true } }` alongside `@{ NAME = ''value'' }`. A secret variable''s value is never read back, compared or logged. - CI - The integration test workflow no longer admits pull requests from forks. Both `integration-tests.yml` jobs require the pull request''s head repository to be this repository in addition to the `resource-add/` branch prefix, and the test framework configuration step refuses to fall back to Managed Identity on a `pull_request` run (it throws if `AZURE_DEVOPS_PAT` is empty). Previously a fork''s code could have run on the self-hosted runner under the runner VM''s identity. - Both integration workflows wipe the module cache directory before the run and, in a final `if: always()` step, remove it again and restore `tests/Integration/TestFrameworkConfiguration.json` from git, so neither `ModuleSettings.clixml` nor the plain-text PAT survives the job on the runner. - `publish.yml` token permissions moved from workflow level to job level; only the `publish` job holds `contents: write` and `pull-requests: write`; the release-gate jobs on the self-hosted runners get `contents: read`. - `actions/checkout`, `actions/cache` and `actions/upload-artifact` are pinned to commit SHAs (v4.4.0, v4.3.0, v4.6.2) in every workflow. - New `script-analysis` job in `unit-tests.yml` runs PSScriptAnalyzer 1.24.0 over `source/Classes`, `source/Modules` and `source/Enum` with the security-focused rule set in the new `PSScriptAnalyzerSettings.psd1`; any finding fails the job. ### Changed - Documentation - `docs/ResourceRoadmap.md` gains §12, the resources a code review found missing that neither the roadmap nor an open issue tracked: permission resources for the `Collection`, `MetaTask`, `ServiceHooks`, `AuditLog`, `EventSubscription` and `VersionControlItems` namespaces and for deployment groups and project agent queues; `AzDoWorkItemTemplate` and `AzDoTaskboardColumn`; `AzDoAgent`, agent pool maintenance and per-pipeline settings on `AzDoPipeline`; `AzDoTestResultRetentionSettings` and organization-wide feed permissions; and project properties and notification delivery settings. It also records what was checked and found already covered or not buildable, and a suggested order. §2, §8 and §9 point to it. - `docs/ResourceRoadmap.md` gains §13 for open issues #66 (Copilot code review) and #67 (GitHub Advanced Security), which the roadmap did not mention. It lists the proposed resources and the questions each issue must settle first, and gives an order. §8 and §9 point to it. - Tests - The integration tests for `AzDoDashboard`, `AzDoOrganizationPermission` and `AzDoTaskGroupPermission` now read the live state back from the REST API after each `Set`, instead of relying only on the resource''s own `Test`: - `AzDoDashboard`: the written description and refresh interval, no duplicate on a repeated `Set`, a widget added outside DSC surviving an update, drift made outside DSC being detected and fixed, and a team and a project dashboard with the same name being kept apart. - `AzDoOrganizationPermission`: the exact allow and deny bits, and every other entry on the organization root compared mask for mask against a snapshot taken before any write - after a `Set`, a second group''s `Set`, a repeated `Set` and `Absent`. Also outside drift, permissions named by display name, and `Absent` removing only its own group''s entry. - `AzDoTaskGroupPermission`: the same live-ACL checks on the project-level token, several identities in one configuration, changing a permission from `Deny` to `Allow`, turning inheritance off and back on, and a project that does not exist. - `New-AzDoAuthenticationProvider.tests.ps1` uses `$TestDrive` instead of a `C:\` path, so it passes on Linux. The known Linux-only failure count in the Common suite drops from 28 to 9 (the remaining `C:\`-path tests in `Export-CacheObject.tests.ps1` and `Initialize-CacheObject.tests.ps1`). ### Fixed - AzureDevOpsDscNative - Reloading a cache no longer writes the whole cache to the output stream ([issue #55](https://github.com/ZanattaMichael/AzureDevOpsDsc/issues/55)). `Import-CacheObject` returns the collection it imported, and `Initialize-CacheObject`, `Refresh-CacheObject` and `Refresh-AzDoCache` called it for its side effect without discarding that value. Every `New-` and `Set-` function that ends by refreshing its cache printed the cache as a `Key`/`Value` table during `Invoke-DscResource`. - `Get-AzDoProjectServices` reports `NotFound` for a project that does not exist, rather than failing with `TF200016`. Its live fallback lookup now goes through `Resolve-AzDoProject`, which treats a 404 as no project. - SecureStrings are decoded correctly on Linux and macOS. `PtrToStringAuto` reads a BSTR as UTF-8 off Windows and returned garbage in `Add-AuthenticationHTTPHeader` (managed-identity cache restore), `Get-AzManagedIdentityToken` (cached token reuse), `Get-AzServicePrincipalCertificateToken` (the PFX password, so the PFX path did not work on Linux at all) and `AzDevOpsDscResourceBase.Construct()` (Workload Identity Federation manual-token restore). All of them, and `Get-AzServicePrincipalToken`, now use the new private helper `ConvertFrom-AzDoSecureString`. - `Get-AzDoVariableGroup` detects drift in `Description` and `Variables` (' } # End of PSData hashtable } # End of PrivateData hashtable } |