5.3 Package Views, Immutability & Quality Promotion
Key Takeaways
- Feed views act as filtered, read-only subsets of an Azure Artifacts feed, allowing organizations to share only vetted, production-ready package versions with downstream consumers.
- Azure Artifacts strictly enforces package immutability: once a package ID and version string (e.g., 2.1.0) are published, they cannot be modified, overwritten, or re-published under any circumstances.
- The default view hierarchy comprises @local (all directly published and upstream packages), @prerelease (packages under testing/validation), and @release (certified, production-ready packages).
- Quality promotion is a metadata operation that links an existing package version to a higher view (e.g., @release) without rebuilding binaries or modifying version identifiers, ensuring build reproducibility.
- Role-Based Access Control (RBAC) separates duties: Reader grants read/restore access (typically scoped to @release), Contributor allows publishing and promoting, and Owner manages feed policies and views.
5.3 Package Views, Immutability & Quality Promotion
Quick Summary: In enterprise DevOps, teams must never release unvetted packages directly to downstream consumers. However, creating separate feeds for development, staging, and production violates package immutability and creates operational overhead. Azure Artifacts solves this through Feed Views—read-only, filtered subsets of a single feed. In Exam AZ-400, candidates must master package immutability, default views (
@local,@prerelease,@release), automated promotion via REST APIs and Azure Pipelines, and feed RBAC roles.
The Architectural Dilemma: Multiple Feeds vs. Feed Views
When teams begin formalizing their release processes, a common architectural temptation is to create separate feeds for each stage of the development lifecycle:
Multi-Feed Anti-Pattern (DO NOT IMPLEMENT):
[Build Pipeline] ──► Push ──► [Dev-Feed]
│
▼ (Re-download & re-push)
[Test-Feed]
│
▼ (Re-download & re-push)
[Prod-Feed]
Why the Multi-Feed Architecture Fails
- Violation of Package Immutability: Moving a package between separate physical feeds requires downloading the package binary, extracting it, and republishing it to the next feed. This process often changes metadata, invalidates digital code signatures, and breaks cryptographic checksums.
- Rebuilding Creates Non-Deterministic Binaries: Some teams attempt to "rebuild from source" for production feeds. This directly violates the core continuous delivery principle: Build binaries once, promote them through environments unchanged. A rebuild produces new compiler timestamps, differing assembly hashes, and potential dependency drift.
- Broken Dependency Graphs: In multi-feed architectures, downstream consumers must continually update their package manager endpoints (
nuget.configor.npmrc) depending on which environment they are testing in. - Storage Duplication & Inefficiency: Storing identical multi-gigabyte package binaries across three separate feeds triples storage costs and complicates audit compliance.
The Solution: Feed Views
Feed Views provide a 1:N projection over a single physical feed. Instead of copying packages across physical repositories, packages remain stored once in the feed. A view acts as a filtered, read-only lens that exposes only those package versions that have attained a specific level of testing, validation, and maturity.
Feed View Architecture (The Azure Artifacts Standard):
+-----------------------------------------------------------------------------+
| Azure Artifacts Feed: [Shared-Enterprise-Components] |
| |
| Physical Storage (Immutable): |
| - Contoso.Core 1.0.0 (Promoted to: @local, @prerelease, @release) |
| - Contoso.Core 1.1.0-preview (Promoted to: @local, @prerelease) |
| - Contoso.Core 1.2.0-nightly (Visible only in: @local) |
| - Newtonsoft.Json 13.0.3 (Upstream cached in: @local) |
+-----------------------------------------------------------------------------+
│ │ │
▼ View: @local ▼ View: @prerelease ▼ View: @release
[All packages & upstreams] [Validated by QA/Staging] [Certified for Production]
Endpoints: Endpoints: Endpoints: .../Shared-Enterprise-
.../Shared-Enterprise- .../Shared-Enterprise- Components@release/...
Components/nuget/v3/index.json Components@prerelease/...
The Built-In Views & The Quality Promotion Lifecycle
Azure Artifacts provides three default, built-in views representing stages in the software maturity lifecycle:
1. @local
- Purpose: The default entry point and working view of the feed.
- Contents: Every package published directly into the feed enters
@localautomatically. Furthermore, all packages retrieved and cached from external upstream sources (such asnuget.orgornpmjs.com) reside in@local. - Audience: Developers testing bleeding-edge builds, experimental branches, and nightly CI integration pipelines.
2. @prerelease
- Purpose: Represents packages that have successfully compiled, passed static code analysis (SonarQube), and passed initial automated unit tests.
- Contents: Contains package versions explicitly promoted from
@localthat are deemed ready for broader integration testing, quality assurance (QA), and user acceptance testing (UAT). - Audience: QA test automation rigs, staging environment deployment pipelines, and external pilot integration teams.
3. @release
- Purpose: The highest quality gate in the organization.
- Contents: Only packages that have completed all functional validation, compliance scanning (e.g., license audits, container scanning, secret detection), performance benchmarking, and formal change-management approvals are promoted here.
- Audience: Production deployment pipelines and general downstream consumers. Consuming applications configure their package managers to target the
@releaseview endpoint, ensuring they never accidentally restore a development snapshot or untested pre-release build.
Custom Views
Organizations can create custom views (up to a maximum of 10 views per feed). Common custom view patterns include:
@lts: Long-Term Support packages maintained for multi-year regulatory releases.@fast-track: For internal early-adopter teams testing upcoming APIs.@deprecated: Flagging packages slated for retirement.
Consuming Feed Views via URLs
To consume a specific view, append the view name prefixed with an @ symbol to the feed segment in the endpoint URL:
# Consuming the root feed (includes all @local packages): https://pkgs.dev.azure.com/{org}/{proj}/_packaging/{feed}/nuget/v3/index.json
# Consuming the @release view exclusively: https://pkgs.dev.azure.com/{org}/{proj}/_packaging/{feed}@release/nuget/v3/index.json
# Consuming the @prerelease view: https://pkgs.dev.azure.com/{org}/{proj}/_packaging/{feed}@prerelease/nuget/v3/index.json
When a downstream project configures its nuget.config or .npmrc to point to @release, the package manager cannot even see packages in @local or @prerelease. If a package version has not been promoted to @release, any attempt to restore it returns 404 Not Found.
The Package Immutability Principle
A cornerstone of modern DevOps and supply chain integrity is Package Immutability:
Core Rule: Once a package with a specific identifier and version string (e.g.,
Contoso.Security 2.4.0) is published to Azure Artifacts, that version is permanently immutable. It can never be overwritten, modified, updated, or re-published.
The Mechanics of 409 Conflict
If a developer discovers a bug in Contoso.Security 2.4.0 thirty minutes after pushing it, rebuilds the package locally, and attempts to re-push the identical version 2.4.0:
# Developer attempts to push updated package with same version
dotnet nuget push Contoso.Security.2.4.0.nupkg --source "CoreFeed"
# Output:
# Response status code does not indicate success: 409 (Conflict - The feed already contains 'Contoso.Security 2.4.0').
Azure Artifacts immediately terminates the upload with HTTP 409 Conflict. This behavior is deliberate and non-bypassable:
- Deleting the package does not free the version number: If an administrator deletes
Contoso.Security 2.4.0from the feed, it is moved to the Recycle Bin. Even if the package is permanently purged from the Recycle Bin, Azure Artifacts permanently reserves the version identifier. The feed will continue to reject any future push of version2.4.0. - Why Immutability Matters for Auditing & Reproducibility: If versions could be overwritten, two developers building the same commit hash could receive different binary logic depending on when they ran
dotnet restore. A rogue developer or compromised CI pipeline could overwrite a legitimate library with backdoored code without changing the version number. - The Only Valid Solution: The developer must increment the version number according to Semantic Versioning (e.g., to
2.4.1for a bug fix) and publish the new version.
Package Quality Promotion Workflows
Promoting a package version does not alter package binaries, recalculate hashes, or change version numbers. Instead, promotion is a lightweight metadata operation that attaches a view label (@prerelease or @release) to the existing package record in the feed database.
Package Promotion Sequence:
1. CI Build Stage:
- Compile code & run unit tests
- Pack Contoso.Core 2.1.0
- Push to Azure Artifacts (Lands in @local)
2. Automated QA Stage:
- Restore from @local
- Run integration & regression test suites
- Tests Pass ──► Promote Contoso.Core 2.1.0 to @prerelease
3. Staging / UAT Stage:
- Test applications restore from @prerelease
- Security scanning & compliance approval passes
- Approval Granted ──► Promote Contoso.Core 2.1.0 to @release
4. Production:
- Production applications restore strictly from @release
Methods of Promotion
- Azure DevOps Web Interface: Navigate to Artifacts > Select Feed > Select Package > Select Version > Click Promote > Select target view (
@prereleaseor@release). - Azure CLI: Using the
az artifactscommand:az artifacts package nuget promote \ --organization "https://dev.azure.com/contoso" \ --project "RetailBanking" \ --feed "CoreComponents" \ --name "Contoso.Core" \ --version "2.1.0" \ --view "release" - Azure DevOps REST API (Recommended for Automated Pipelines): Automated multi-stage YAML pipelines use the packaging REST API to promote packages programmatically after quality gates pass.
REST API Promotion Payload
PATCH https://feeds.dev.azure.com/{organization}/{project}/_apis/packaging/feeds/{feedId}/nuget/packages/{packageName}/versions/{packageVersion}?api-version=7.1-preview.1
Content-Type: application/json
{
"views": {
"op": "add",
"path": "/views/-",
"value": "release"
}
}
Production-Grade Multi-Stage YAML Pipeline with Quality Promotion Gate
The following YAML pipeline demonstrates an end-to-end promotion workflow. It builds and packs a NuGet library, tests it in a staging environment, and automatically promotes it to @release upon successful staging verification:
# azure-pipelines-promotion.yml
trigger:
branches:
include:
- main
pool:
vmImage: 'windows-latest'
variables:
feedName: 'RetailBanking/EnterpriseFeed'
packageName: 'Contoso.Financial.Core'
packageVersion: '3.2.0'
stages:
- stage: BuildAndPublish
displayName: 'Build, Pack & Publish to @local'
jobs:
- job: BuildJob
steps:
- task: DotNetCoreCLI@2
displayName: 'Compile Solution'
inputs:
command: 'build'
projects: '**/*.csproj'
arguments: '--configuration Release'
- task: DotNetCoreCLI@2
displayName: 'Pack NuGet Package'
inputs:
command: 'pack'
packagesToPack: '**/*.csproj'
versioningScheme: 'off'
outputDir: '$(Build.ArtifactStagingDirectory)'
- task: NuGetAuthenticate@1
displayName: 'Authenticate with Azure Artifacts'
- task: DotNetCoreCLI@2
displayName: 'Publish Package to Feed (@local)'
inputs:
command: 'push'
packagesToPush: '$(Build.ArtifactStagingDirectory)/*.nupkg'
publishVstsFeed: '$(feedName)'
- stage: QualityValidation
displayName: 'Automated Integration Testing'
dependsOn: BuildAndPublish
jobs:
- job: TestJob
steps:
- script: echo "Running automated integration, regression, and security scans..."
displayName: 'Execute Test Suite'
- stage: PromoteToRelease
displayName: 'Promote Package to @release'
dependsOn: QualityValidation
condition: succeeded()
jobs:
- job: PromoteJob
steps:
- task: PowerShell@2
displayName: 'Promote to @release View via REST API'
inputs:
targetType: 'inline'
script: |
$org = "$(System.CollectionUri)"
$project = "$(System.TeamProject)"
$feed = "EnterpriseFeed"
$pkg = "$(packageName)"
$ver = "$(packageVersion)"
$token = "$(System.AccessToken)"
$url = "https://feeds.dev.azure.com/$(System.TeamProject)/_apis/packaging/feeds/$feed/nuget/packages/$pkg/versions/$ver`?api-version=7.1-preview.1"
$headers = @{
Authorization = "Bearer $token"
"Content-Type" = "application/json"
}
$body = @{
views = @{
op = "add"
path = "/views/-"
value = "release"
}
} | ConvertTo-Json
Invoke-RestMethod -Uri $url -Method Patch -Headers $headers -Body $body
Write-Host "Successfully promoted $pkg $ver to @release view."
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
Feed Permissions, Roles & Segregation of Duties
Azure Artifacts uses an explicit Role-Based Access Control (RBAC) model to enforce security boundaries and compliance requirements (e.g., Sarbanes-Oxley 404 segregation of duties).
Feed Role Hierarchy & Capabilities:
[Reader]
└── Query, read, and restore packages from feed or designated views
[Collaborator]
└── Inherits Reader + Ability to save/cache packages from external Upstream Sources
[Contributor]
└── Inherits Collaborator + Push new packages, unlist packages, and promote packages to views
[Owner]
└── Inherits Contributor + Edit feed settings, add/remove upstreams, manage views, configure RBAC
Role Definitions & Capabilities
| Feed Role | Can Read Packages? | Can Save Upstream Packages? | Can Push / Publish Packages? | Can Promote to Views? | Can Manage Views & Permissions? |
|---|---|---|---|---|---|
| Reader | Yes | No | No | No | No |
| Collaborator | Yes | Yes | No | No | No |
| Contributor | Yes | Yes | Yes | Yes | No |
| Owner | Yes | Yes | Yes | Yes | Yes |
Configuring Pipeline Identities for Packaging
Azure Pipelines builds authenticate to feeds using the project's build identity:
Project Collection Build Service ({OrgName})(for organization-scoped access){ProjectName} Build Service ({OrgName})(for project-scoped access)
To ensure proper segregation of duties:
- Publishing Pipelines: The build pipeline that compiles and publishes packages must be assigned the Contributor role on the feed to allow pushing packages to
@localand promoting versions. - Consuming Pipelines: Downstream application pipelines must be assigned only the Reader role, scoped strictly to the
@releaseview endpoint. This guarantees downstream pipelines cannot accidentally push untracked packages or promote unvetted versions. - Human Developers: Enterprise teams typically grant developers Reader permissions on internal feeds and require all new package releases to pass through automated build pipelines rather than allowing direct workstation pushes.
Practical AZ-400 Exam Scenarios & Anti-Patterns
Scenario 1: Handling HTTP 409 on Hotfix Publishing
- Scenario: A developer discovers a critical defect in
Contoso.Auth 1.2.0immediately after publishing. They attempt to overwrite the package by re-runningdotnet nuget push, which fails with409 Conflict. They then delete1.2.0from the feed UI and retry pushing, but the push continues to fail. - AZ-400 Solution: Explain package immutability. Azure Artifacts reserves the version string permanently, even after deletion from the recycle bin. The developer must increment the version to
1.2.1(or1.2.0.1), compile, and publish the new version.
Scenario 2: Restricting Production Pipelines to Certified Dependencies
- Scenario: An enterprise requires that production deployment pipelines restore only packages that have been formally reviewed, security-audited, and approved by the architecture board. Staging pipelines must be able to test upcoming candidates without exposing them to production.
- AZ-400 Solution: Configure feed views in Azure Artifacts. Core builds publish candidates to
@local. When candidates pass automated integration testing, promote them to@prerelease. After architectural review, promote them to@release. Configure production applicationnuget.configfiles to point strictly to the.../CoreFeed@release/...endpoint.
A developer notices a bug in an internal NuGet package version 2.3.0 that was pushed to an Azure Artifacts feed 30 minutes ago. The developer fixes the bug locally, builds a new .nupkg file with the identical version 2.3.0, and executes 'dotnet nuget push'. The push fails with HTTP 409 Conflict. The developer deletes the package from the feed and tries again, but it still fails. What is the cause of this behavior, and what is the proper resolution?
An enterprise DevOps architect needs to ensure that production application deployment pipelines consume only security-vetted, production-certified versions of internal shared libraries. However, the core library engineering team must be able to publish daily continuous integration builds without creating multiple independent feeds that duplicate storage and require binary re-packaging. Which architecture should the architect implement?
An automated multi-stage Azure Pipelines YAML file publishes a shared NuGet library in its first stage and must promote the package to the @release view in a subsequent deployment stage after integration tests pass. What is the minimum Role-Based Access Control (RBAC) role that the pipeline's Build Service account must possess on the target Azure Artifacts feed to promote the package version?