diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..23bdd489 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,220 @@ +name: Release + +# Builds a 0.1.0-alpha prerelease of azureauth-unofficial from main-v2 and creates a +# draft GitHub prerelease. The repository owner reviews and publishes each draft by hand. +# docs/delivery-wave.md ("Windows 0.1.0-alpha Prereleases") authorizes this workflow and +# bounds its permissions, assets and effects; the Windows design owns the package. + +on: + workflow_dispatch: + +permissions: {} + +concurrency: + group: release + cancel-in-progress: false + +env: + # The mise version CI pins; keep it equal to MISE_VERSION in check.yml. + MISE_VERSION: 2026.10.22 + +jobs: + build: + name: Build and package + runs-on: windows-latest + timeout-minutes: 45 + permissions: + contents: read + outputs: + version: ${{ steps.version.outputs.version }} + commit: ${{ steps.version.outputs.commit }} + env: + DOTNET_CLI_TELEMETRY_OPTOUT: "1" + TESTINGPLATFORM_TELEMETRY_OPTOUT: "1" + DOTNET_NOLOGO: "1" + MISE_EXEC_AUTO_INSTALL: "false" + + steps: + - name: Refuse any ref other than main-v2 + if: github.ref != 'refs/heads/main-v2' + run: | + Write-Error "Release builds run only from refs/heads/main-v2." + exit 1 + + - name: Check out the repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # Nerdbank.GitVersioning computes the product version from the full history. + fetch-depth: 0 + persist-credentials: false + + - name: Install mise + uses: jdx/mise-action@c2a87611a18de5b3828c5652fe268e992400cb5c # v4.3.0 + with: + version: ${{ env.MISE_VERSION }} + install: false + # Never restore a cache into a release build. + cache: false + + - name: Install the pinned .NET SDK + run: mise install --locked http:dotnet-development + + - name: Restore with the committed lock files + run: mise exec -- dotnet restore Windows.slnx --locked-mode + + - name: Build + run: mise exec -- dotnet build Windows.slnx --configuration Release --no-restore + + - name: Create a fresh scenario temporary directory + run: New-Item -ItemType Directory -Path "${{ runner.temp }}\scenarios" + + - name: Run the Windows synthetic scenarios without host-timing assertions + run: >- + mise exec -- dotnet + tests/Authentication.Windows.Scenarios/bin/Release/net10.0-windows/Authentication.Windows.Scenarios.dll + --filter "TestCategory!=WindowsHostTiming" + env: + TEMP: ${{ runner.temp }}\scenarios + TMP: ${{ runner.temp }}\scenarios + + - name: Package + run: >- + mise exec -- pwsh -NoProfile -File packaging/windows/package.ps1 + -OutputDirectory "${{ runner.temp }}\package" + + - name: Record the version and the build chain + id: version + env: + PACKAGE: ${{ runner.temp }}\package + run: | + $zip = @(Get-ChildItem -LiteralPath $env:PACKAGE -Filter 'azureauth-unofficial-*-win-x64.zip') + if ($zip.Count -ne 1) { throw "expected one package zip, found $($zip.Count)" } + if ($zip[0].Name -notmatch '^azureauth-unofficial-(0\.1\.0-alpha\.(0|[1-9][0-9]*))-win-x64\.zip$') { + throw "unexpected package name $($zip[0].Name)" + } + $version = $Matches[1] + $commit = (git rev-parse HEAD).Trim() + $vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe' + # The ILCompiler package finds Visual Studio with vswhere -latest -prerelease; match it. + $vsArgs = @('-latest', '-prerelease', '-products', '*', '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64') + $vs = & $vswhere @vsArgs -property installationPath + $vsVersion = & $vswhere @vsArgs -property catalog_productDisplayVersion + $msvc = (Get-Content -LiteralPath (Join-Path $vs 'VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt')).Trim() + $link = (Get-Item -LiteralPath (Join-Path $vs "VC\Tools\MSVC\$msvc\bin\Hostx64\x64\link.exe")).VersionInfo.FileVersion + $kits = Join-Path ${env:ProgramFiles(x86)} 'Windows Kits\10\Lib' + $sdks = @(Get-ChildItem -LiteralPath $kits -Directory | + Where-Object { Test-Path (Join-Path $_.FullName 'um\x64') } | + ForEach-Object { $_.Name } | Sort-Object { [version]$_ }) + $info = [ordered]@{ + version = $version + commit = $commit + runnerImage = "$env:ImageOS $env:ImageVersion" + dotnetSdk = (mise exec -- dotnet --version).Trim() + visualStudio = $vsVersion + msvc = $msvc + linkExe = $link + windowsSdks = $sdks + } + $json = $info | ConvertTo-Json + Set-Content -LiteralPath (Join-Path $env:PACKAGE 'build-info.json') -Value $json + Write-Host $json + Add-Content -LiteralPath $env:GITHUB_STEP_SUMMARY -Value @('## Build chain', '', '```json', $json, '```') + Add-Content -LiteralPath $env:GITHUB_OUTPUT -Value @("version=$version", "commit=$commit") + + - name: Upload the package for the next jobs + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: package + path: ${{ runner.temp }}\package\* + if-no-files-found: error + # The owner accepted at most one day of exposure; nothing deletes them earlier. + retention-days: 1 + + attest: + name: Attest build provenance + needs: build + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + id-token: write + attestations: write + steps: + - name: Download the package + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: package + path: package + + - name: Attest both zips + uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 + with: + subject-path: package/*.zip + + draft: + name: Create the draft prerelease + needs: [build, attest] + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: write + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + VERSION: ${{ needs.build.outputs.version }} + COMMIT: ${{ needs.build.outputs.commit }} + steps: + - name: Download the package + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: package + path: package + + - name: Verify the checksums and the recorded commit + working-directory: package + run: | + sha256sum --check -- *.sha256 + test "$(jq -r .commit build-info.json)" = "$COMMIT" + test "$(jq -r .version build-info.json)" = "$VERSION" + + - name: Refuse an existing tag, release or draft + # bash -eo pipefail, so a failed lookup in a pipeline stops the run. + shell: bash + run: | + # Only a 404 means absent; any other failure stops the run. + absent() { + local err + if err=$(gh api "$1" 2>&1 >/dev/null); then return 1; fi + if grep -q 'HTTP 404' <<<"$err"; then return 0; fi + echo "$err" >&2 + exit 1 + } + absent "repos/$GH_REPO/git/ref/tags/v$VERSION" || { echo "Tag v$VERSION already exists." >&2; exit 1; } + absent "repos/$GH_REPO/releases/tags/v$VERSION" || { echo "A published release v$VERSION already exists." >&2; exit 1; } + drafts=$(gh api --paginate "repos/$GH_REPO/releases" --jq "[.[] | select(.tag_name == \"v$VERSION\")] | length" | awk '{ n += $1 } END { print n + 0 }') + if [ "$drafts" -ne 0 ]; then echo "A release or draft for v$VERSION already exists." >&2; exit 1; fi + + - name: Create the draft prerelease + run: | + { + echo "**azureauth-unofficial $VERSION** is an unsupported alpha prerelease of" + echo "[AzureAuth Unofficial V2](https://github.com/$GH_REPO), an independent, unofficial" + echo "fork of Microsoft Authentication CLI. It is not a Microsoft product and has no" + echo "support, production-readiness or compatibility commitment." + echo + echo "- Built from commit $COMMIT by this repository's release workflow. The zips carry" + echo " [GitHub build-provenance attestations](https://github.com/$GH_REPO/attestations)." + echo "- The executables are not code-signed. Compare each zip with its .sha256 file" + echo " before extracting." + echo "- The package bundles the Microsoft-owned Visual Studio public client as an opt-in" + echo " Client Profile. Sign-in, consent and audit records show Visual Studio; Microsoft" + echo " provides no support or availability commitment for it." + echo "- The -symbols.zip holds the native and managed symbol files for diagnosing this" + echo " build; it is not needed to run it." + echo + echo "Read the [package README](https://github.com/$GH_REPO/blob/$COMMIT/packaging/windows/README.md)" + echo "before use. The release review for this prerelease is recorded on" + echo "[Issue #506](https://github.com/$GH_REPO/issues/506)." + } > notes.md + gh release create "v$VERSION" --draft --prerelease --target "$COMMIT" \ + --title "azureauth-unofficial $VERSION" --notes-file notes.md \ + package/*.zip package/*.sha256 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4474af22..c93abced 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -132,7 +132,9 @@ pwsh packaging/windows/package.ps1 ``` The [Windows design](docs/designs/windows-ado-authentication.md#portable-package-and-version) -owns the package content and checks. +owns the package content and checks. Prereleases are built only by the +[release workflow](docs/designs/windows-ado-authentication.md#release-workflow), started by +hand from `main-v2`; the repository owner publishes each draft after its release review. ## .NET and Agent Tooling @@ -147,7 +149,8 @@ management waits for a concrete product consumer. `mise.lock` is generator output: never edit it by hand. Generate it with the mise version that CI pins, the `MISE_VERSION` value in `.github/workflows/check.yml`; -`mise.toml` sets the same `min_version`. Another mise +`mise.toml` sets the same `min_version`, and `.github/workflows/release.yml` uses the same +`MISE_VERSION`. Another mise version can rewrite unrelated entries. To change the SDK, edit its version and each platform's archive URL and `checksum` in diff --git a/README.md b/README.md index 533cb1ac..37cf0130 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,8 @@ Start with: ## Windows Portable Package The Windows x64 command is `azureauth-unofficial`, built as an unsigned portable zip -that you extract into a directory of your choice. No package has been published yet. The +that you extract into a directory of your choice. Unsupported `0.1.0-alpha` prereleases +may be published on this repository's GitHub Releases page after a release review. The [package README](packaging/windows/README.md) covers installation, use from Windows and WSL, the bundled Visual Studio compatibility Profile and its limits, and removal. diff --git a/docs/README.md b/docs/README.md index 99e0d3f7..a29d4c6e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -47,7 +47,7 @@ is navigation, not an independent authority. | Design and validation reviewers | Completed synthetic Native AOT publish, upstream native-import, and public Native AOT assessment evidence | [`windows-native-aot.md`](research/experiments/windows-native-aot.md) | | Validation and design reviewers | Completed Windows Slice selected-account, WSL, and host observation evidence and its public-source basis | [`windows-slice-validation.md`](research/experiments/windows-slice-validation.md) | | Validation, design, and security reviewers | Completed 2026-10-15 real-host validation method, results, limitations, and deviation dispositions for the `main-v2` Windows product | [`real-host-validation.md`](research/experiments/real-host-validation.md) | -| Experiment operators and validation reviewers | Host test protocol, attempt ledger, and results for the locally built Windows portable package | [`portable-package-host-test.md`](research/experiments/portable-package-host-test.md) | +| Validation, design, and security reviewers | Completed 2026-10-29 host test method, results, limitations, and deviation dispositions for the locally built Windows portable package | [`portable-package-host-test.md`](research/experiments/portable-package-host-test.md) | | Research and release reviewers | Mutable public facts and their recheck triggers | [`research/rechecks.yaml`](research/rechecks.yaml) | | Maintainers and upstream-source consumers | Upstream baseline and import policy | [`../UPSTREAM.md`](../UPSTREAM.md) | diff --git a/docs/designs/windows-ado-authentication.md b/docs/designs/windows-ado-authentication.md index 9f59d0dc..902adf6a 100644 --- a/docs/designs/windows-ado-authentication.md +++ b/docs/designs/windows-ado-authentication.md @@ -92,11 +92,15 @@ exact upstream loader, its dependencies, and the process search restriction must validated together on the actual application; an incompatible loader makes the target unavailable rather than silently weakening search rules or copying private runtime internals. -A product publish must pin the Windows x64 public native build chain -(Visual Studio C++ tools, Windows SDK, and `link.exe`), SDK/runtime inputs, resolved -NuGet graph, and publish properties before execution. Microsoft's documented Windows -prerequisite is Visual Studio 2022 or later with Desktop development with C++ and its default -components; this record does not select a floating installed compiler. Artifact closure must include the native broker and +A product publish must pin the SDK/runtime inputs, resolved NuGet graph, and publish +properties before execution, and must pin the Windows x64 public native build chain +(Visual Studio C++ tools, Windows SDK, and `link.exe`). Microsoft's documented Windows +prerequisite is Visual Studio 2022 or later with Desktop development with C++ and its +default components; this record does not select a floating installed compiler. The one +exception: for `0.1.0-alpha` prereleases the repository owner accepted the floating chain +of the GitHub-hosted runner image instead of pinning it; the +[release workflow](#release-workflow) records the installed chain on every run and the +release review checks it. Artifact closure must include the native broker and OS prerequisites; an AOT executable does not imply one-file deployment or no OS dependency. Debug symbols have a separate diagnostic/release treatment and are included when comparing total development and distribution costs. @@ -190,6 +194,30 @@ Version computation needs a full Git clone: a shallow clone fails the build, and without `.git`, such as a `git archive` copy, does not build. CI therefore checks out with `fetch-depth: 0`. + +### Release Workflow + +`.github/workflows/release.yml` builds `0.1.0-alpha` prereleases. It starts only by hand +and, in its `main-v2` copy, refuses any ref other than `refs/heads/main-v2`, so the build +is a public release. A copy of the workflow on another ref is not bound by that guard; +the release review checks that the run and its attestation come from +`.github/workflows/release.yml` at `refs/heads/main-v2` and the built commit. + +Its jobs have least privilege. The build job reads contents only. It restores in locked +mode with the checksum-pinned SDK, runs the Windows scenarios excluding +`WindowsHostTiming`, runs `package.ps1` without its development switches, and records in +`build-info.json` and the run summary the runner image, the .NET SDK, and the installed +chain that the Native AOT linker resolves: the Visual Studio that `vswhere -latest +-prerelease` finds, as ILCompiler does, its default MSVC toolset and `link.exe`, and the +installed Windows SDKs. That this is the chain the linker used is an inference. A second +job holds only `id-token: write` and `attestations: write` and creates a GitHub +build-provenance attestation for both zips. A third holds only `contents: write`: it +verifies the checksums and the recorded commit, refuses a version whose tag, release or +draft exists (failing on any lookup error other than not found), and creates a draft +prerelease `v` targeting the built commit, with the package zip, the symbols zip +and their `.sha256` files. The jobs pass files as workflow artifacts kept for one day. +The repository owner publishes each draft after the release review. + ## Protocol 1 Command-Line Contract Invoke ` authenticate` followed by the arguments below. Options and enum diff --git a/docs/governance/controls.yaml b/docs/governance/controls.yaml index 1580aac6..eee6fa64 100644 --- a/docs/governance/controls.yaml +++ b/docs/governance/controls.yaml @@ -326,6 +326,37 @@ controls: - ci failure_mode: A Windows adapter, CLI or Windows scenario change merges without compiling, or with a synthetic Windows scenario failing, because only the platform-neutral projects ran in CI. + - id: windows-release-workflow + state: current + class: mechanical + enforcement: blocking + producer: GitHub Actions Release workflow + maintainer: Control maintainer + consumers: + - Repository owner and the independent release reviewer before a draft prerelease is published + governing_rules: + - docs/governance/governance-system.md#gov-005-controls-implement-policy + - docs/governance/project.md#support-and-release + - docs/product/requirements/quality-build-and-validation.md#v2-req-053-public-build-chain + - docs/designs/windows-ado-authentication.md#release-workflow + invariant: >- + The main-v2 copy of the workflow drafts a 0.1.0-alpha prerelease only for a manually + started run on refs/heads/main-v2 that restored from public package sources in locked mode with the + checksum-pinned SDK, passed every tests/Authentication.Windows.Scenarios scenario + outside the WindowsHostTiming category, passed every package.ps1 check without its + development switches, recorded its installed native build chain, attested both zips, targets + the built commit, and uses a version with no existing tag, release or draft. Each job holds + only the token permissions its step needs. Publication stays the repository owner's + decision after the release review, which also checks that the run and its attestation + come from that workflow at refs/heads/main-v2. + runner: github-platform + implementation: + kind: repository-path + value: .github/workflows/release.yml + execution_points: + - release + failure_mode: A prerelease is drafted from an unreviewed ref, a failing build, an unattested or mismatched asset, or a token broader than the step needs. + - id: record-system-review state: current class: procedural-review diff --git a/docs/governance/operational-identities.yaml b/docs/governance/operational-identities.yaml index fc931d55..b539ce27 100644 --- a/docs/governance/operational-identities.yaml +++ b/docs/governance/operational-identities.yaml @@ -122,7 +122,9 @@ selected_v2: owning_component: packaging/windows/package.ps1 location: >- Archive file name, with a SHA-256 checksum file named after the archive with a - .sha256 suffix. + .sha256 suffix. A symbols archive azureauth-unofficial--win-x64-symbols.zip + with its own .sha256 file holds the build's native and managed symbol files and is + published beside it. version_behavior: >- is the computed SemVer 2.0 version without build metadata, for example 0.1.0-alpha.42; the archive name changes with each version. @@ -210,8 +212,9 @@ selected_v2: Prerelease assets of this repository's GitHub Releases. The product never checks for, downloads or applies updates. version_behavior: >- - Each prerelease archive carries the computed SemVer 2.0 version without build - metadata in its name. The later release entry selects the tag scheme. + Each prerelease is tagged v, where is the computed SemVer 2.0 + version without build metadata (for example v0.1.0-alpha.42), on the built commit; + its archives carry the same version in their names. collision_test: >- Upstream update channels are the AzureAD/microsoft-authentication-cli releases and their installers; this channel is a different repository and archive name. diff --git a/docs/governance/project.md b/docs/governance/project.md index 6cf8737b..a8601b56 100644 --- a/docs/governance/project.md +++ b/docs/governance/project.md @@ -41,8 +41,12 @@ Until those identities are selected: ## Support and Release -The repository currently provides no published v2 release, production-readiness claim, -or service-level objective. +Unsupported `0.1.0-alpha` prereleases of the Windows `azureauth-unofficial` package may +be published as GitHub prereleases, built by the +[release workflow](../../.github/workflows/release.yml) and published by the repository +owner after a release review. They carry no support, production-readiness or +compatibility claim, and the repository provides no supported v2 release or +service-level objective. A future support claim must identify the exact release, platform, account state, client application, mechanism, dependency set, and validation evidence to which it applies. diff --git a/docs/governance/record-families.yaml b/docs/governance/record-families.yaml index 356cdc7b..4dac3f1e 100644 --- a/docs/governance/record-families.yaml +++ b/docs/governance/record-families.yaml @@ -456,20 +456,19 @@ families: failure_mode: Current conclusions cite real-host observations whose scope, evidence level, limitations, or deviations can no longer be read, or the observations are extended beyond the observed roles, callers, subjects, host, and existing state. review_point: Independent research-evidence review when a citing conclusion changes or the evidence is corrected - - id: portable-package-host-test-protocol + - id: portable-package-host-test-evidence state: current - concern: Accepted protocol, attempt ledger, and sanitized results for the host test of the locally built Windows portable package + concern: Completed 2026-10-29 host test of the locally built Windows portable package, with its accepted protocol as method, sanitized results, bounded conclusions, limitations, and deviation dispositions carrier: repository-file path: docs/research/experiments/portable-package-host-test.md format: markdown producer: Validation maintainer maintainer: Validation maintainer consumers: - - Repository owner and operator executing the bounded host calls - Validation, design, and security reviewers relying on the recorded observations and their limitations - creation_trigger: The Delivery Wave entry "Windows Portable Package, Local Build and Test" requires an accepted protocol before any real call with the packaged archive. - failure_mode: Real calls run outside the accepted subject, effects, or limits, or their evidence leaks private data or overstates scope. - review_point: Independent research-evidence review of every protocol amendment and results change + creation_trigger: Issue #506 produced host-test observations of the portable package that the validation strategy cites; the protocol and its execution history remain in Git. + failure_mode: Current conclusions cite host-test observations whose scope, evidence level, limitations, or deviations can no longer be read, or the observations are extended beyond the observed roles, callers, subject, host, and existing state. + review_point: Independent research-evidence review when a citing conclusion changes or the evidence is corrected - id: developer-tooling-evidence state: current diff --git a/docs/product/user-stories.md b/docs/product/user-stories.md index b18b1657..31063a9b 100644 --- a/docs/product/user-stories.md +++ b/docs/product/user-stories.md @@ -26,7 +26,9 @@ engine under [decision 0004](../decisions/0004-keep-the-authentication-engine-se The engine's PAT prohibition is governed by [V2-REQ-005](requirements/product-boundary.md#v2-req-005-no-personal-access-tokens). -This is the primary first-release blocking journey. Its acceptance evidence belongs to +This is the primary first-release blocking journey; "first release" means the first +supported, non-prerelease release, so unsupported `0.1.0-alpha` prereleases are exempt. +Its acceptance evidence belongs to the [primary-journey validation gate](../validation/strategy.md#primary-journey-gate). The WAM context explains the wrong-default risk; it does not select WAM as the required implementation or establish that any Client Profile or platform supports this journey. diff --git a/docs/research/experiments/portable-package-host-test.md b/docs/research/experiments/portable-package-host-test.md index 94b58679..b13ddebf 100644 --- a/docs/research/experiments/portable-package-host-test.md +++ b/docs/research/experiments/portable-package-host-test.md @@ -1,12 +1,14 @@ -# Portable Package Host Test Protocol - -This protocol governs item 4 of the Delivery Wave entry -[Windows Portable Package, Local Build and Test](../../delivery-wave.md), coordinated in -[Issue #506](https://github.com/hcoona/microsoft-authentication-cli/issues/506). It follows -the [experiment policy](../experiment-safety.md). Merging it into `main-v2` is the protocol -acceptance; it adds no product, support or release claim. The Wave entry owns the owner -risk decisions, the circuit-breaker limits and the exclusions; this record only narrows -them. Results are appended under [Results](#results) through reviewed pull requests. +# Portable Package Host Test Evidence + +This is a completed experiment record for +[Issue #506](https://github.com/hcoona/microsoft-authentication-cli/issues/506), retained as +evidence cited by current records. It authorizes no execution. It ran under the Delivery +Wave entry "Windows Portable Package, Local Build and Test", whose text remains in +[`docs/delivery-wave.md` at commit `a7ece22`](https://github.com/hcoona/microsoft-authentication-cli/blob/a7ece22222480d4938a48a2ade803f3728ed97ff/docs/delivery-wave.md); +[PR #549](https://github.com/hcoona/microsoft-authentication-cli/pull/549) removed that +entry on 2026-10-29. The accepted protocol below is kept as the method of the recorded +results; the [experiment policy](../experiment-safety.md) governs any future experiment, +and another run requires a new accepted protocol and authorization. The question is whether the archive that `packaging/windows/package.ps1` builds, once extracted into a fresh directory, authenticates the existing personal and work roles on @@ -388,7 +390,9 @@ installation or remote effect outside the protocol was observed. ### Retention -The package and symbols zips with their `.sha256` files stay in -`C:\Temp\azureauth-pkgtest-20261029\out` until this record merges, then the root is deleted -as Retention and Cleanup requires. The local launchers, `roles.json` and ledger stay until -the Wave entry ends. Capacity remaining under the Wave limits: 34 I and 49 N. +After [PR #548](https://github.com/hcoona/microsoft-authentication-cli/pull/548) merged on +2026-10-29, the SDK build servers were stopped and `C:\Temp\azureauth-pkgtest-20261029` (source, +packages, HTTP cache, both zips, extraction directory and validator) was deleted, together +with the local launchers, `roles.json`, ledger and the WSL launcher's temporary +directories. WAM sessions and caches were retained. The experiment ended with 34 I and +49 N unused. diff --git a/docs/security/threat-model.md b/docs/security/threat-model.md index 4c1816c8..3b485bab 100644 --- a/docs/security/threat-model.md +++ b/docs/security/threat-model.md @@ -88,7 +88,7 @@ threat model owns their security assumptions and mitigation tradeoffs. | A caller directs discovery or authentication to an attacker-controlled authority. | [`V2-REQ-011A`](../product/requirements/request-identity-and-authority.md#v2-req-011a-trusted-authority) | | Home-tenant identity is mistaken for the requested resource tenant, or token parsing fabricates scope satisfaction. | [`V2-REQ-019`](../product/requirements/request-identity-and-authority.md#v2-req-019-tenant-selection), [`V2-REQ-027`](../product/requirements/request-identity-and-authority.md#v2-req-027-scope-satisfaction), and [`V2-REQ-033`](../product/requirements/result-and-process-protocol.md#v2-req-033-opaque-access-tokens) | | Telemetry sends without explicit configuration or changes the authentication outcome. | [`V2-REQ-043`](../product/requirements/cache-security-and-operational-identity.md#v2-req-043-no-upstream-telemetry-reuse) and [`V2-REQ-046`](../product/requirements/cache-security-and-operational-identity.md#v2-req-046-optional-telemetry-semantics) | -| A compromised or substituted input to the product build (a NuGet package, the .NET SDK, or a GitHub Action in a build or test job) or an over-privileged CI token alters what is built or tested. | [`V2-REQ-053`](../product/requirements/quality-build-and-validation.md#v2-req-053-public-build-chain) and the existing mitigations: [`check.yml`](../../.github/workflows/check.yml) pins every action to a full commit SHA, grants only `contents: read` and checks out without persisted credentials; every restore runs in locked mode against the committed `packages.lock.json` files with the NuGet.org-only source mapping in [`nuget.config`](../../nuget.config); and [`mise.lock`](../../mise.lock) pins the SDK archive checksums. Repository check tooling is outside this product threat model; [contributor tooling](../../CONTRIBUTING.md#net-and-agent-tooling) governs it and how these pins change. | +| A compromised or substituted input to the product build (a NuGet package, the .NET SDK, or a GitHub Action in a build or test job) or an over-privileged CI token alters what is built or tested. | [`V2-REQ-053`](../product/requirements/quality-build-and-validation.md#v2-req-053-public-build-chain) and the existing mitigations: [`check.yml`](../../.github/workflows/check.yml) pins every action to a full commit SHA, grants only `contents: read` and checks out without persisted credentials; the [release workflow](../../.github/workflows/release.yml) also pins every action, starts only by hand and, in its `main-v2` copy, refuses other refs (the release review checks the attestation's source ref and workflow), checks out without persisted credentials, restores no tool cache, and splits its token by job (build: `contents: read`; attestation: `id-token: write` and `attestations: write`; draft: `contents: write`), attests both zips' build provenance, and only drafts a prerelease that the repository owner publishes after review; every restore runs in locked mode against the committed `packages.lock.json` files with the NuGet.org-only source mapping in [`nuget.config`](../../nuget.config); and [`mise.lock`](../../mise.lock) pins the SDK archive checksums. Repository check tooling is outside this product threat model; [contributor tooling](../../CONTRIBUTING.md#net-and-agent-tooling) governs it and how these pins change. | | Dependency or upstream changes alter broker or cache behavior. | [Dependency Upgrade Matrix](../validation/strategy.md#dependency-upgrade-matrix) and [Release Gates](../validation/strategy.md#release-gates) | | Unofficial artifacts overwrite or impersonate upstream AzureAuth. | [`V2-REQ-003`](../product/requirements/product-boundary.md#v2-req-003-unofficial-product-identity), [`V2-REQ-044`](../product/requirements/cache-security-and-operational-identity.md#v2-req-044-independent-distribution-identity), and decision [`0005`](../decisions/0005-establish-independent-operational-identity.md) | diff --git a/docs/validation/strategy.md b/docs/validation/strategy.md index 99465f60..c38a81c1 100644 --- a/docs/validation/strategy.md +++ b/docs/validation/strategy.md @@ -56,7 +56,10 @@ manual assistance cannot substitute for a capability the product itself must pro ## Primary Journey Gate The [personal Azure DevOps Git journey](../product/user-stories.md#primary-journey-personal-azure-devops-git-access) -is a first-release blocker. Before release, bounded evidence must demonstrate that an +is a first-release blocker: it blocks the first supported, non-prerelease release. +Unsupported `0.1.0-alpha` prereleases are exempt by +[owner decision](https://github.com/hcoona/microsoft-authentication-cli/pull/549#issuecomment-6510282012). +Before that release, bounded evidence must demonstrate that an external adapter can request the selected personal Microsoft account's Azure DevOps access token without silently receiving the corporate default account, and that usable state enables strict selected-account silent reuse across invocations. @@ -542,7 +545,9 @@ checks: The Windows scenarios' wall-clock process assertions, such as the one-second shutdown allowance and process-exit bounds, carry the `WindowsHostTiming` category. They are Windows host-timing evidence: they establish timing only on the host where they ran. No -CI job runs them, and the `windows-latest` job makes no host-timing claim. A passing +CI job runs them, and the `windows-latest` job makes no host-timing claim. The +[release workflow](../designs/windows-ado-authentication.md#release-workflow) runs the same +scenarios with the same filter before packaging and makes the same limited claim. A passing Windows CI run establishes the synthetic Windows behavior on that runner image only; it is not real-platform, broker or published-executable evidence. Every Windows scenario run, in CI or on a host, uses a new empty temporary directory as @@ -608,7 +613,8 @@ The [host test of the locally built archive](../research/experiments/portable-pa passed every case it reached for both roles from native and WSL callers in existing state on the designated host; interaction-required was reached only for the personal native caller, and one forced-interactive call timed out with its prompt unidentified. It is -that bounded evidence only. +that bounded evidence only. Publishing `0.1.0-alpha` prereleases from the release workflow +closes none of these gates either. The Slice explicitly excludes browser/device code, Linux forwarding/native brokers, non-Public Cloud, service/impersonated/disconnected Windows sessions, ARM64, Profile