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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ updates:
patterns:
- "xunit*"
- "Microsoft.NET.Test.Sdk"
- "Microsoft.Testing.*"
- "NSubstitute"
- "Shouldly"
- "Microsoft.AspNetCore.Mvc.Testing"
Expand Down
18 changes: 16 additions & 2 deletions .github/workflows/cd-cleanup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,27 @@ jobs:
matrix:
env: [ci, ppe]
steps:
- uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0
- name: Skip if tier never bootstrapped
id: precheck
env:
AZURE_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }}
run: |
if [ -z "${AZURE_CLIENT_ID}" ]; then
echo "::notice title=Cleanup skipped (${{ matrix.env }})::AZURE_CLIENT_ID not set on this GitHub Environment; tier never bootstrapped."
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi

- if: steps.precheck.outputs.skip == 'false'
uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}

- name: Reset min/max replicas in rg-ftgo-${{ matrix.env }}-${{ vars.LOCATION || 'eastus' }}
- if: steps.precheck.outputs.skip == 'false'
name: Reset min/max replicas in rg-ftgo-${{ matrix.env }}-${{ vars.LOCATION || 'eastus' }}
env:
LOCATION: ${{ vars.LOCATION || 'eastus' }}
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ jobs:

- name: Upload Trivy SARIF
if: always()
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
uses: github/codeql-action/upload-sarif@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
with:
sarif_file: trivy-${{ steps.meta.outputs.SHORT_NAME }}.sarif
category: trivy-${{ steps.meta.outputs.SHORT_NAME }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ jobs:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: DavidAnson/markdownlint-cli2-action@992badcdf24e3b8eb7e87ff9287fe931bcb00c6e # v20.0.0
- uses: DavidAnson/markdownlint-cli2-action@6b51ade7a9e4a75a7ad929842dd298a3804ebe8b # v23.1.0
with:
globs: |
**/*.md
Expand All @@ -203,7 +203,7 @@ jobs:
issues: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: lycheeverse/lychee-action@82202e5e9c2f4ef1a55a3d02563e1cb6041e5332 # v2.7.0
- uses: lycheeverse/lychee-action@8646ba30535128ac92d33dfc9133794bfdd9b411 # v2.7.0
with:
args: --no-progress --max-concurrency 4 --exclude-mail './**/*.md'
fail: false
70 changes: 70 additions & 0 deletions .github/workflows/drift-detection.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: drift-detection

# Weekly Bicep what-if against ci/ppe to surface infrastructure drift between
# what main says is deployed and what's actually live in Azure. Output is a
# job summary annotation; no auto-remediation.

on:
schedule:
- cron: '0 6 * * 1' # Mondays 06:00 UTC
workflow_dispatch:

permissions:
contents: read

concurrency:
group: drift-${{ github.ref }}
cancel-in-progress: true

jobs:
what-if:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
id-token: write
contents: read
strategy:
fail-fast: false
matrix:
env: [ci, ppe]
environment: ${{ matrix.env }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Azure login
uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}

- name: Skip if RG missing (tier never provisioned)
id: rg-check
env:
RG: rg-ftgo-${{ matrix.env }}-${{ vars.LOCATION || 'eastus' }}
run: |
if ! az group show --name "$RG" --only-show-errors --output none 2>/dev/null; then
echo "::notice title=Drift skipped::$RG does not exist; tier never provisioned."
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi

- name: Bicep what-if
if: steps.rg-check.outputs.skip == 'false'
env:
RG: rg-ftgo-${{ matrix.env }}-${{ vars.LOCATION || 'eastus' }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
run: |
set -euo pipefail
out=$(az deployment group what-if \
--resource-group "$RG" \
--template-file infra/bicep/azure.bicep \
--parameters infra/bicep/azure.${{ matrix.env }}.bicepparam \
--no-pretty-print --result-format ResourceIdOnly 2>&1) || true
echo "$out"
if echo "$out" | grep -qE '^(\+|\-|\~|=) '; then
echo "::warning title=Drift detected (${{ matrix.env }})::Bicep what-if reports differences against $RG. Review the run log."
else
echo "::notice title=No drift (${{ matrix.env }})::Live state matches main."
fi
2 changes: 1 addition & 1 deletion .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@ jobs:
retention-days: 5

- name: Upload to code-scanning
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
uses: github/codeql-action/upload-sarif@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
with:
sarif_file: results.sarif
1 change: 1 addition & 0 deletions .markdownlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ MD040: false
MD028: false
MD036: false
MD031: false
MD060: false
14 changes: 7 additions & 7 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<ItemGroup Label="ASP.NET Core / Microsoft.Extensions">
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.7" />
<PackageVersion Include="Scalar.AspNetCore" Version="2.14.4" />
<PackageVersion Include="Scalar.AspNetCore" Version="2.14.9" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="10.0.7" />
Expand All @@ -19,8 +19,8 @@
</ItemGroup>

<ItemGroup Label="Identity / Azure">
<PackageVersion Include="Microsoft.Identity.Web" Version="4.8.0" />
<PackageVersion Include="Microsoft.Identity.Web.DownstreamApi" Version="4.8.0" />
<PackageVersion Include="Microsoft.Identity.Web" Version="4.9.0" />
<PackageVersion Include="Microsoft.Identity.Web.DownstreamApi" Version="4.9.0" />
<PackageVersion Include="Microsoft.Identity.Abstractions" Version="12.0.0" />
<PackageVersion Include="Microsoft.Identity.Client" Version="4.83.3" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.17.0" />
Expand All @@ -39,19 +39,19 @@
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.15.1" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.1" />
<PackageVersion Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.7.0" />
<PackageVersion Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.8.0" />
</ItemGroup>

<ItemGroup Label="Analyzers">
<PackageVersion Include="Meziantou.Analyzer" Version="3.0.54" />
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.24.0.138807" />
<PackageVersion Include="Meziantou.Analyzer" Version="3.0.58" />
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.25.0.139117" />
<PackageVersion Include="Roslynator.Analyzers" Version="4.15.0" />
<PackageVersion Include="AsyncFixer" Version="2.1.0" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="10.0.203" />
</ItemGroup>

<ItemGroup Label="Testing">
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.4.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
<PackageVersion Include="xunit.v3" Version="3.2.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.7" />
Expand Down
20 changes: 10 additions & 10 deletions SCOPE.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,16 @@ Call them out so readers don't expect them.

## 5. "If you are X, this guide is Y for you"

| Reader archetype | Recommendation |
|---|---|
| Staff .NET engineer at a 200-person SaaS, multi-team, cloud-native on Azure | **Primary reader.** Read [`docs/decision-trees.md`](./docs/decision-trees.md) → SCOPE → [`docs/matrix.md`](./docs/matrix.md) → [`docs/best-practices.md`](./docs/best-practices.md). |
| Platform / auth-library owner (`EntraAuth.*` shared NuGet, multi-product) | **Primary reader.** Start at [`docs/aks-shared-infra.md`](./docs/aks-shared-infra.md), then [`docs/acquisition.md`](./docs/acquisition.md) and [`docs/validation.md`](./docs/validation.md). |
| Architect picking credential type for a new service | **Primary reader.** [`docs/decision-trees.md`](./docs/decision-trees.md) Tree 2 + Tree 5 → [`docs/credential-patterns/index.md`](./docs/credential-patterns/index.md). |
| Solo developer, one app, pre-PMF | **Skim only.** [`docs/run-locally.md`](./docs/run-locally.md) and [`docs/best-practices.md`](./docs/best-practices.md) are worth an hour; the platform / shared-infra chapters are premature. |
| ASP.NET Core engineer needing JWT validation defaults only | **Targeted reader.** [`docs/validation.md`](./docs/validation.md) is the chapter; the rest is background. |
| Mobile / SPA developer | **Wrong guide.** Read MSAL.js or MSAL mobile docs first; come back when you own a server-side .NET API. |
| IGA / access-review engineer | **Wrong guide.** Use [Microsoft Entra ID Governance](https://learn.microsoft.com/entra/id-governance/identity-governance-overview); this guide is for app developers, not directory operators. |
| Compliance / GRC reviewer mapping controls | **Reference, not source of truth.** Use this as the engineering-side counterpart to your control catalog; mapping work is yours. |
| Reader archetype | Recommendation |
| --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Staff .NET engineer at a 200-person SaaS, multi-team, cloud-native on Azure | **Primary reader.** Read [`docs/decision-trees.md`](./docs/decision-trees.md) → SCOPE → [`docs/matrix.md`](./docs/matrix.md) → [`docs/best-practices.md`](./docs/best-practices.md). |
| Platform / auth-library owner (`EntraAuth.*` shared NuGet, multi-product) | **Primary reader.** Start at [`docs/aks-shared-infra.md`](./docs/aks-shared-infra.md), then [`docs/acquisition.md`](./docs/acquisition.md) and [`docs/validation.md`](./docs/validation.md). |
| Architect picking credential type for a new service | **Primary reader.** [`docs/decision-trees.md`](./docs/decision-trees.md) Tree 2 + Tree 5 → [`docs/credential-patterns/index.md`](./docs/credential-patterns/index.md). |
| Solo developer, one app, pre-PMF | **Skim only.** [`docs/run-locally.md`](./docs/run-locally.md) and [`docs/best-practices.md`](./docs/best-practices.md) are worth an hour; the platform / shared-infra chapters are premature. |
| ASP.NET Core engineer needing JWT validation defaults only | **Targeted reader.** [`docs/validation.md`](./docs/validation.md) is the chapter; the rest is background. |
| Mobile / SPA developer | **Wrong guide.** Read MSAL.js or MSAL mobile docs first; come back when you own a server-side .NET API. |
| IGA / access-review engineer | **Wrong guide.** Use [Microsoft Entra ID Governance](https://learn.microsoft.com/entra/id-governance/identity-governance-overview); this guide is for app developers, not directory operators. |
| Compliance / GRC reviewer mapping controls | **Reference, not source of truth.** Use this as the engineering-side counterpart to your control catalog; mapping work is yours. |

---

Expand Down
Loading
Loading