Repository navigation
Website #62
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: KeyLoad website | |
| on: | |
| push: | |
| branches: [main] | |
| paths: ['site/**'] | |
| workflow_run: | |
| workflows: [KeyLoad CI] | |
| branches: [main] | |
| types: [completed] | |
| workflow_dispatch: | |
| inputs: | |
| mode: | |
| description: Qualify candidate website, or publish the current main website | |
| required: true | |
| default: validate | |
| type: choice | |
| options: [validate, publish] | |
| evidence_run: | |
| description: Historical comparison run for validation only; blank selects latest comparison | |
| required: false | |
| type: string | |
| isolated_evidence_run: | |
| description: Historical isolated aggregate run for validation only; blank selects latest qualified cohort | |
| required: false | |
| type: string | |
| permissions: | |
| contents: read | |
| actions: read | |
| concurrency: | |
| group: keyload-pages | |
| cancel-in-progress: false | |
| jobs: | |
| qualify: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 180 | |
| outputs: | |
| mode: ${{ steps.source.outputs.mode }} | |
| site_revision: ${{ steps.source.outputs.revision }} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| EVIDENCE_DIR: ${{ github.workspace }}/artifacts/site-evidence | |
| KEYLOAD_SITE_REPOSITORY: ${{ github.workspace }}/website | |
| KEYLOAD_SITE_GITHUB_CAPTURE: ${{ github.workspace }}/artifacts/site-evidence/github-capture | |
| KEYLOAD_SITE_ARCHIVE: ${{ github.workspace }}/artifacts/site-evidence/comparison-suite.zip | |
| KEYLOAD_SITE_ARCHIVE_RECEIPT: ${{ github.workspace }}/artifacts/site-evidence/archive-receipt.json | |
| KEYLOAD_SITE_REPORTS: ${{ github.workspace }}/artifacts/comparisons | |
| KEYLOAD_SITE_COVERAGE: ${{ github.workspace }}/artifacts/site-evidence/js-coverage | |
| KEYLOAD_SITE_ISOLATED_CAPTURE: ${{ github.workspace }}/artifacts/site-evidence/isolated-capture | |
| KEYLOAD_SITE_ISOLATED_ARCHIVE_RECEIPT: ${{ github.workspace }}/artifacts/site-evidence/isolated-capture/archive-receipt.json | |
| KEYLOAD_SITE_ISOLATED_AGGREGATE: ${{ github.workspace }}/artifacts/site-evidence/isolated-capture/input/aggregate | |
| steps: | |
| - name: Checkout trusted workflow control source | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| ref: ${{ github.workflow_sha }} | |
| path: control | |
| persist-credentials: false | |
| - name: Select website source and authenticated comparison evidence | |
| id: source | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| REQUESTED_MODE: ${{ inputs.mode }} | |
| REQUESTED_RUN: ${{ inputs.evidence_run }} | |
| ISOLATED_REQUESTED_RUN: ${{ inputs.isolated_evidence_run }} | |
| CONTROL_REVISION: ${{ github.workflow_sha }} | |
| shell: bash | |
| run: | | |
| mode=publish | |
| if [[ "$EVENT_NAME" == workflow_dispatch ]]; then mode="$REQUESTED_MODE"; fi | |
| revision="$GITHUB_SHA" | |
| if [[ "$mode" == publish ]]; then | |
| [[ "$GITHUB_REF" == refs/heads/main && -z "$REQUESTED_RUN" && -z "$ISOLATED_REQUESTED_RUN" ]] | |
| revision=$(timeout 120s gh api "repos/$GH_REPO/git/ref/heads/main" --jq .object.sha) | |
| fi | |
| [[ "$revision" =~ ^[a-f0-9]{40}$ && "$CONTROL_REVISION" =~ ^[a-f0-9]{40}$ ]] | |
| printf 'mode=%s\nrevision=%s\n' "$mode" "$revision" >> "$GITHUB_OUTPUT" | |
| printf 'KEYLOAD_SITE_SOURCE_REVISION=%s\n' "$revision" >> "$GITHUB_ENV" | |
| printf 'KEYLOAD_SITE_CONTROL_REVISION=%s\n' "$CONTROL_REVISION" >> "$GITHUB_ENV" | |
| args=("--input=$KEYLOAD_SITE_GITHUB_CAPTURE" "--mode=$mode" "--site-revision=$revision" "--workflow-revision=$CONTROL_REVISION") | |
| if [[ -n "$REQUESTED_RUN" ]]; then args+=("--requested-run=$REQUESTED_RUN"); fi | |
| bash control/scripts/Features/BenchmarkComparisons/collect-github-evidence.sh "${args[@]}" | |
| proof="$KEYLOAD_SITE_GITHUB_CAPTURE/metadata-proof.json" | |
| artifact_id=$(jq -er '.artifact.id' "$proof") | |
| [[ "$artifact_id" =~ ^[1-9][0-9]*$ ]] | |
| timeout 120s gh api "repos/$GH_REPO/actions/artifacts/$artifact_id/zip" > "$KEYLOAD_SITE_ARCHIVE" | |
| node control/scripts/Features/BenchmarkComparisons/github-evidence.mjs verify-archive --receipt="$proof" --archive="$KEYLOAD_SITE_ARCHIVE" > "$EVIDENCE_DIR/archive-envelope.json" | |
| jq -e '.ok == true' "$EVIDENCE_DIR/archive-envelope.json" | |
| jq '.result' "$EVIDENCE_DIR/archive-envelope.json" > "$KEYLOAD_SITE_ARCHIVE_RECEIPT" | |
| printf 'KEYLOAD_SITE_EVIDENCE_RUN=%s\nKEYLOAD_SITE_MEASURED_REVISION=%s\n' "$(jq -r '.run.id' "$proof")" "$(jq -r '.measuredSourceRevision' "$proof")" >> "$GITHUB_ENV" | |
| printf 'measured_revision=%s\n' "$(jq -r '.measuredSourceRevision' "$proof")" >> "$GITHUB_OUTPUT" | |
| isolated_args=("--input=$KEYLOAD_SITE_ISOLATED_CAPTURE" "--mode=$mode" "--site-revision=$revision" "--workflow-revision=$CONTROL_REVISION") | |
| if [[ -n "$ISOLATED_REQUESTED_RUN" ]]; then isolated_args+=("--requested-run=$ISOLATED_REQUESTED_RUN"); fi | |
| node control/scripts/Features/BenchmarkComparisons/site-isolated-github-cli.mjs capture "${isolated_args[@]}" > "$EVIDENCE_DIR/isolated-capture-envelope.json" | |
| jq -e '.ok == true' "$EVIDENCE_DIR/isolated-capture-envelope.json" > /dev/null | |
| isolated_proof="$KEYLOAD_SITE_ISOLATED_CAPTURE/metadata-proof.json" | |
| printf 'KEYLOAD_SITE_ISOLATED_MEASURED_REVISION=%s\n' "$(jq -er '.source.measured' "$isolated_proof")" >> "$GITHUB_ENV" | |
| printf 'isolated_measured_revision=%s\n' "$(jq -er '.source.measured' "$isolated_proof")" >> "$GITHUB_OUTPUT" | |
| - name: Checkout website source | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| ref: ${{ steps.source.outputs.revision }} | |
| path: website | |
| persist-credentials: false | |
| - name: Inspect measured producer source | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| ref: ${{ steps.source.outputs.measured_revision }} | |
| path: measured | |
| persist-credentials: false | |
| - name: Inspect isolated measured producer source | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| ref: ${{ steps.source.outputs.isolated_measured_revision }} | |
| path: measured-isolated | |
| persist-credentials: false | |
| - name: Verify checkouts and retain runtime/source receipts | |
| shell: bash | |
| run: | | |
| [[ "$(git -C website rev-parse HEAD)" == "$KEYLOAD_SITE_SOURCE_REVISION" ]] | |
| [[ "$(git -C measured rev-parse HEAD)" == "$KEYLOAD_SITE_MEASURED_REVISION" ]] | |
| [[ "$(git -C measured-isolated rev-parse HEAD)" == "$KEYLOAD_SITE_ISOLATED_MEASURED_REVISION" ]] | |
| test -f measured/.github/workflows/ci.yml | |
| git -C website rev-parse HEAD > "$EVIDENCE_DIR/website-revision.txt" | |
| git -C measured rev-parse HEAD > "$EVIDENCE_DIR/measured-revision.txt" | |
| git -C control rev-parse HEAD > "$EVIDENCE_DIR/control-revision.txt" | |
| git -C measured-isolated rev-parse HEAD > "$EVIDENCE_DIR/isolated-measured-revision.txt" | |
| tools=(collect-github-evidence.sh github-evidence-contracts.mjs github-evidence-runs.mjs github-evidence-proof.mjs github-evidence.mjs) | |
| for file in "${tools[@]}"; do | |
| relative="scripts/Features/BenchmarkComparisons/$file" | |
| cmp "control/$relative" "website/$relative" | |
| sha256sum "website/$relative" >> "$EVIDENCE_DIR/executed-evidence-tools.sha256" | |
| done | |
| closure="scripts/Features/BenchmarkComparisons/site-isolated-dependencies.txt" | |
| cmp "control/$closure" "website/$closure" | |
| [[ "$(wc -l < "control/$closure")" == 49 ]] | |
| LC_ALL=C sort -u "control/$closure" > "$EVIDENCE_DIR/isolated-dependencies.txt" | |
| cmp "control/$closure" "$EVIDENCE_DIR/isolated-dependencies.txt" | |
| sha256sum "website/$closure" >> "$EVIDENCE_DIR/executed-evidence-tools.sha256" | |
| while IFS= read -r relative; do | |
| [[ "$relative" =~ ^(scripts/Features/BenchmarkComparisons/[^/]+\.mjs|site/Features/BenchmarkComparisons/[^/]+\.mjs|benchmarks/KeyLoad.Comparisons/Features/BenchmarkComparisons/isolated-contract\.json)$ ]] | |
| for root in control website; do | |
| [[ -f "$root/$relative" && ! -L "$root/$relative" ]] | |
| [[ "$(realpath -e "$root/$relative")" == "$GITHUB_WORKSPACE/$root/$relative" ]] | |
| done | |
| cmp "control/$relative" "website/$relative" | |
| sha256sum "website/$relative" >> "$EVIDENCE_DIR/executed-isolated-dependencies.sha256" | |
| done < "control/$closure" | |
| for file in AGENTS.md action.yml; do | |
| relative=".github/workflows/Features/BenchmarkComparisons/BuildIsolatedSite/$file" | |
| cmp "control/$relative" "website/$relative" | |
| sha256sum "website/$relative" >> "$EVIDENCE_DIR/executed-evidence-tools.sha256" | |
| done | |
| cp measured/.github/workflows/ci.yml "$EVIDENCE_DIR/measured-producer.yml" | |
| cp measured-isolated/.github/workflows/ci.yml "$EVIDENCE_DIR/isolated-measured-producer.yml" | |
| node --version > "$EVIDENCE_DIR/node-version.txt" | |
| chrome=$(command -v google-chrome || command -v google-chrome-stable || command -v chromium || command -v chromium-browser) | |
| test -n "$chrome" && test -x "$chrome" | |
| "$chrome" --version > "$EVIDENCE_DIR/browser-version.txt" | |
| printf 'KEYLOAD_SITE_BROWSER=%s\n' "$chrome" >> "$GITHUB_ENV" | |
| mkdir -p "$KEYLOAD_SITE_COVERAGE/node" | |
| cd website | |
| git ls-files -z | xargs -0 sha256sum > "$EVIDENCE_DIR/source.sha256" | |
| - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 | |
| with: | |
| global-json-file: website/global.json | |
| - name: Qualify required analyzer dependency | |
| working-directory: website | |
| shell: bash | |
| run: | | |
| dotnet --info > "$EVIDENCE_DIR/dotnet-info.txt" | |
| pwsh --version > "$EVIDENCE_DIR/powershell-version.txt" | |
| dotnet restore tests/KeyLoad.Analyzers.Tests/KeyLoad.Analyzers.Tests.csproj | |
| dotnet build tests/KeyLoad.Analyzers.Tests/KeyLoad.Analyzers.Tests.csproj --no-restore --configuration Release | |
| mkdir -p "$EVIDENCE_DIR/analyzer-coverage" | |
| cp scripts/Features/CodeQuality/site-analyzer-coverage.settings.xml "$EVIDENCE_DIR/analyzer-coverage/coverage.config.xml" | |
| pwsh -NoProfile -File scripts/Features/CodeQuality/site-analyzer-coverage.ps1 -Mode Prepare -Repository "$KEYLOAD_SITE_REPOSITORY" -Contract "$KEYLOAD_SITE_REPOSITORY/scripts/Features/CodeQuality/site-analyzer-coverage.contract.json" -EvidenceRoot "$EVIDENCE_DIR/analyzer-coverage" | |
| dotnet test --project tests/KeyLoad.Analyzers.Tests --no-build --no-restore --configuration Release --report-trx --results-directory "$EVIDENCE_DIR/analyzer-tests" --coverage --coverage-settings "$EVIDENCE_DIR/analyzer-coverage/coverage.config.xml" --coverage-output-format cobertura --coverage-output "$EVIDENCE_DIR/analyzer-coverage/coverage.cobertura.xml" | |
| - name: Enforce native analyzer coverage counts | |
| if: success() || failure() | |
| working-directory: website | |
| shell: pwsh | |
| run: ./scripts/Features/CodeQuality/site-analyzer-coverage.ps1 -Mode Verify -Repository "$env:KEYLOAD_SITE_REPOSITORY" -Contract "$env:KEYLOAD_SITE_REPOSITORY/scripts/Features/CodeQuality/site-analyzer-coverage.contract.json" -EvidenceRoot "$env:EVIDENCE_DIR/analyzer-coverage" -CoverageReport "$env:EVIDENCE_DIR/analyzer-coverage/coverage.cobertura.xml" | |
| - name: Restore and build independent site qualification | |
| working-directory: website | |
| run: | | |
| dotnet restore tests/KeyLoad.SiteTests/KeyLoad.SiteTests.csproj | |
| dotnet build tests/KeyLoad.SiteTests/KeyLoad.SiteTests.csproj --no-restore --configuration Release | |
| - name: Verify focused format and governance | |
| working-directory: website | |
| shell: bash | |
| run: | | |
| dotnet format src/KeyLoad.Analyzers/KeyLoad.Analyzers.csproj --verify-no-changes --no-restore --severity warn --verbosity minimal > "$EVIDENCE_DIR/format-analyzers.txt" 2>&1 | |
| dotnet format tests/KeyLoad.Analyzers.Tests/KeyLoad.Analyzers.Tests.csproj --verify-no-changes --no-restore --severity warn --verbosity minimal > "$EVIDENCE_DIR/format-analyzer-tests.txt" 2>&1 | |
| dotnet format tests/KeyLoad.SiteTests/KeyLoad.SiteTests.csproj --verify-no-changes --no-restore --severity warn --verbosity minimal > "$EVIDENCE_DIR/format-site-tests.txt" 2>&1 | |
| node scripts/Features/RepositoryGovernance/verify.mjs | |
| - name: Run full site TUnit suite with mandatory same-archive preparation | |
| working-directory: website | |
| env: | |
| NODE_V8_COVERAGE: ${{ github.workspace }}/artifacts/site-evidence/js-coverage/node | |
| run: dotnet test --project tests/KeyLoad.SiteTests --no-build --no-restore --configuration Release --report-trx --results-directory "$EVIDENCE_DIR/site-tests" | |
| - name: Require complete passing test receipts without skips | |
| shell: pwsh | |
| run: | | |
| $receipts = foreach ($suite in @('analyzer-tests', 'site-tests')) { | |
| $files = @(Get-ChildItem -LiteralPath "$env:EVIDENCE_DIR/$suite" -Filter '*.trx' -File) | |
| if ($files.Count -ne 1) { throw "Expected exactly one $suite TRX receipt" } | |
| [xml]$document = Get-Content -LiteralPath $files[0].FullName -Raw | |
| $counts = $document.TestRun.ResultSummary.Counters | |
| if ($null -eq $counts -or [int]$counts.total -le 0 -or | |
| [int]$counts.executed -ne [int]$counts.total -or | |
| [int]$counts.passed -ne [int]$counts.total) { | |
| throw "Incomplete or failing $suite qualification; skipped tests cannot pass" | |
| } | |
| [ordered]@{ suite = $suite; total = [int]$counts.total; executed = [int]$counts.executed; passed = [int]$counts.passed; sha256 = (Get-FileHash -LiteralPath $files[0].FullName -Algorithm SHA256).Hash.ToLowerInvariant() } | |
| } | |
| ConvertTo-Json -InputObject @($receipts) -Depth 4 | Set-Content -LiteralPath "$env:EVIDENCE_DIR/test-receipts.json" -Encoding utf8NoBOM | |
| - name: Build exact qualified historical and isolated website | |
| uses: ./control/.github/workflows/Features/BenchmarkComparisons/BuildIsolatedSite | |
| - name: Upload exact qualified Pages output | |
| if: success() && steps.source.outputs.mode == 'publish' | |
| uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 | |
| with: | |
| path: _site | |
| - name: Retain all qualification and provenance evidence | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: site-qualification-${{ steps.source.outputs.revision }}-${{ github.run_attempt }} | |
| path: | | |
| _site | |
| artifacts/site-evidence | |
| website/artifacts/code-quality/KeyLoad.SiteTests | |
| website/artifacts/code-quality/KeyLoad.Analyzers | |
| website/artifacts/code-quality/KeyLoad.Analyzers.Tests | |
| website/tests/KeyLoad.Analyzers.Tests/bin/Release/net10.0/KeyLoad.Analyzers.dll | |
| website/tests/KeyLoad.Analyzers.Tests/bin/Release/net10.0/KeyLoad.Analyzers.pdb | |
| deploy: | |
| needs: qualify | |
| if: needs.qualify.result == 'success' && needs.qualify.outputs.mode == 'publish' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 90 | |
| permissions: | |
| contents: read | |
| actions: read | |
| pages: write | |
| id-token: write | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deployment.outputs.page_url }} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| ref: ${{ github.workflow_sha }} | |
| path: control | |
| persist-credentials: false | |
| - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 | |
| with: | |
| name: site-qualification-${{ needs.qualify.outputs.site_revision }}-${{ github.run_attempt }} | |
| path: qualification | |
| - name: Recheck current website and immutable comparison evidence | |
| env: | |
| QUALIFIED_REVISION: ${{ needs.qualify.outputs.site_revision }} | |
| CONTROL_REVISION: ${{ github.workflow_sha }} | |
| shell: bash | |
| run: | | |
| revision=$(timeout 120s gh api "repos/$GH_REPO/git/ref/heads/main" --jq .object.sha) | |
| [[ "$revision" == "$QUALIFIED_REVISION" ]] | |
| capture="$GITHUB_WORKSPACE/predeploy-capture" | |
| bash control/scripts/Features/BenchmarkComparisons/collect-github-evidence.sh --input="$capture" --mode=publish --site-revision="$revision" --workflow-revision="$CONTROL_REVISION" | |
| node control/scripts/Features/BenchmarkComparisons/github-evidence.mjs fresh --before="$GITHUB_WORKSPACE/qualification/artifacts/site-evidence/archive-receipt.json" --after="$capture/metadata-proof.json" > predeploy-proof.json | |
| isolated_capture="$GITHUB_WORKSPACE/predeploy-isolated-capture" | |
| node control/scripts/Features/BenchmarkComparisons/site-isolated-github-cli.mjs capture-metadata --input="$isolated_capture" --mode=publish --site-revision="$revision" --workflow-revision="$CONTROL_REVISION" > predeploy-isolated-capture-envelope.json | |
| jq -e '.ok == true' predeploy-isolated-capture-envelope.json > /dev/null | |
| node control/scripts/Features/BenchmarkComparisons/site-isolated-github-cli.mjs fresh --before="$GITHUB_WORKSPACE/qualification/artifacts/site-evidence/isolated-capture/archive-receipt.json" --after="$isolated_capture/metadata-proof.json" > predeploy-isolated-proof.json | |
| jq -e '.ok == true' predeploy-isolated-proof.json > /dev/null | |
| date --utc --iso-8601=seconds > predeploy-checked-at.txt | |
| - uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5 | |
| - name: Publish qualified website | |
| id: deployment | |
| uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 | |
| - name: Record actual Pages deployment result | |
| if: always() | |
| env: | |
| DEPLOYMENT_OUTCOME: ${{ steps.deployment.outcome }} | |
| DEPLOYMENT_URL: ${{ steps.deployment.outputs.page_url }} | |
| SITE_REVISION: ${{ needs.qualify.outputs.site_revision }} | |
| shell: bash | |
| run: | | |
| jq -n --arg outcome "$DEPLOYMENT_OUTCOME" --arg url "$DEPLOYMENT_URL" --arg revision "$SITE_REVISION" --arg run_url "https://github.com/$GH_REPO/actions/runs/$GITHUB_RUN_ID" --argjson attempt "$GITHUB_RUN_ATTEMPT" '{schemaVersion:1,siteSourceRevision:$revision,qualification:{runUrl:$run_url,attempt:$attempt},provider:{outcome:$outcome,pageUrl:$url}}' > deployment-receipt.json | |
| - name: Retain freshness and deployment receipt | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: site-publication-${{ github.run_id }}-${{ github.run_attempt }} | |
| path: | | |
| predeploy-capture | |
| predeploy-proof.json | |
| predeploy-isolated-capture | |
| predeploy-isolated-capture-envelope.json | |
| predeploy-isolated-proof.json | |
| predeploy-checked-at.txt | |
| deployment-receipt.json |