Fix labeler v5+ compatibility, add release documentation badges, update architecture docs#1060
Fix labeler v5+ compatibility, add release documentation badges, update architecture docs#1060
Conversation
…ntation as code Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
…mary Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a tag/dispatch-driven GitHub Actions release pipeline for the static homepage site, including SLSA-related attestations and “documentation as code” outputs committed under docs/.
Changes:
- Introduces
.github/workflows/release.ymlwith a 3-job (prepare/build/release) pipeline producing ZIP + SBOM + attestations and publishing a GitHub Release. - Adds Release Drafter configuration for automated release notes.
- Adds end-user documentation + a
docs/index.htmlviewer describing the workflow and generated reports.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/release.yml |
Implements prepare/build/release pipeline, report generation, artifact packaging, attestations, release + Pages deploy |
.github/release-drafter.yml |
Configures categorized release notes and a release template referencing attestations/SBOM |
docs/index.html |
Adds a static “release documentation” landing page for generated reports |
docs/WORKFLOW_DOCUMENTATION.md |
Detailed workflow usage/permissions/troubleshooting guide |
docs/README.md |
Short description of generated documentation under docs/ |
RELEASE_WORKFLOW_IMPLEMENTATION.md |
Implementation summary and rationale for the workflow |
QUICKSTART_RELEASE.md |
Quickstart instructions for tagging/manual release |
IMPLEMENTATION_COMPLETE.md |
High-level recap of delivered workflow + docs |
| - name: Checkout repository | ||
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| fetch-depth: 0 |
There was a problem hiding this comment.
On tag-triggered runs, actions/checkout will check out the tag ref (detached HEAD). The later git-auto-commit step that commits docs will likely fail or push nowhere unless you explicitly check out the default branch (or set the git-auto-commit-action branch input). Consider checking out ${{ github.event.repository.default_branch }} when the goal is to commit generated docs back to the repo, and keep the tag-derived version separate.
| fetch-depth: 0 | |
| fetch-depth: 0 | |
| ref: ${{ github.event.repository.default_branch }} |
There was a problem hiding this comment.
Fixed in commit a30949c. Added ref: ${{ github.event.repository.default_branch }} to the checkout step to ensure docs are committed to the default branch instead of detached HEAD on tag-triggered runs.
.github/workflows/release.yml
Outdated
| contents: write # Required for git auto-commit | ||
| outputs: | ||
| version: ${{ steps.get-version.outputs.version }} | ||
| is_prerelease: ${{ github.event.inputs.prerelease || 'false' }} |
There was a problem hiding this comment.
is_prerelease is only sourced from workflow_dispatch input, so tag-based pre-releases like v1.0.0-rc.1 will be treated as non-prerelease. If you want tag-based prereleases to work, derive this output from the tag name (e.g., contains(version, '-')) in addition to the dispatch input.
| is_prerelease: ${{ github.event.inputs.prerelease || 'false' }} | |
| is_prerelease: ${{ (github.event_name == 'workflow_dispatch' && github.event.inputs.prerelease) || contains(steps.get-version.outputs.version, '-') }} |
There was a problem hiding this comment.
Fixed in commit a30949c. Updated is_prerelease to detect pre-release from tag name: (github.event_name == 'workflow_dispatch' && github.event.inputs.prerelease) || contains(steps.get-version.outputs.version, '-'). Now automatically detects tags like v1.0.0-rc.1 or v1.0.0-beta.1 as pre-releases.
.github/workflows/release.yml
Outdated
|
|
||
| **Release Date:** $(date -u '+%Y-%m-%d %H:%M:%S UTC') | ||
| **Commit:** \`${{ github.sha }}\` | ||
| **Pre-release:** ${{ steps.get-version.outputs.is_prerelease }} |
There was a problem hiding this comment.
steps.get-version.outputs.is_prerelease is referenced here, but the get-version step only outputs version. This will render blank (and may mislead consumers). Use the job output needs.prepare.outputs.is_prerelease (or compute from the resolved version) instead.
| **Pre-release:** ${{ steps.get-version.outputs.is_prerelease }} | |
| **Pre-release:** ${{ needs.prepare.outputs.is_prerelease }} |
There was a problem hiding this comment.
Fixed in commit a30949c. Changed to use needs.prepare.outputs.is_prerelease instead of the non-existent step output.
.github/workflows/release.yml
Outdated
| # Create the zip file from the website root | ||
| zip -r homepage-${{ needs.prepare.outputs.version }}.zip \ | ||
| *.html \ | ||
| *.css \ | ||
| *.js \ | ||
| *.webp \ | ||
| *.png \ | ||
| *.jpg \ | ||
| *.jpeg \ | ||
| *.gif \ | ||
| *.svg \ | ||
| *.ico \ | ||
| *.xml \ | ||
| *.txt \ | ||
| robots.txt \ | ||
| sitemap.xml \ | ||
| .well-known/ \ | ||
| screenshots/ \ | ||
| docs/ \ |
There was a problem hiding this comment.
The zip command lists many glob patterns (e.g. *.gif, *.svg). If any of these patterns have no matches in the repo root, zip typically exits non-zero ("name not matched"), which will fail the workflow. Prefer zipping the directory (e.g. zip -r ... .) with a clear exclude list, or enable nullglob/generate the file list so optional extensions don’t break the build.
| # Create the zip file from the website root | |
| zip -r homepage-${{ needs.prepare.outputs.version }}.zip \ | |
| *.html \ | |
| *.css \ | |
| *.js \ | |
| *.webp \ | |
| *.png \ | |
| *.jpg \ | |
| *.jpeg \ | |
| *.gif \ | |
| *.svg \ | |
| *.ico \ | |
| *.xml \ | |
| *.txt \ | |
| robots.txt \ | |
| sitemap.xml \ | |
| .well-known/ \ | |
| screenshots/ \ | |
| docs/ \ | |
| # Create the zip file from the website root, excluding non-release files | |
| zip -r homepage-${{ needs.prepare.outputs.version }}.zip . \ |
There was a problem hiding this comment.
Fixed in commit a30949c. Changed to zip -r homepage-$VERSION.zip . -x <exclusions> to zip the entire directory with explicit exclusions. This prevents failures when optional file patterns don't match and is more maintainable.
docs/index.html
Outdated
| <strong>Documentation as Code</strong><br> | ||
| All reports are automatically generated and committed to the repository during the release process. | ||
| View releases and download artifacts at | ||
| <a href="https://github.com/Hack23/homepage/releases" target="_blank">GitHub Releases</a>. |
There was a problem hiding this comment.
External link opened with target="_blank" should include rel="noopener noreferrer" to prevent reverse-tabnabbing and ensure safer cross-origin navigation.
| <a href="https://github.com/Hack23/homepage/releases" target="_blank">GitHub Releases</a>. | |
| <a href="https://github.com/Hack23/homepage/releases" target="_blank" rel="noopener noreferrer">GitHub Releases</a>. |
There was a problem hiding this comment.
Fixed in commit a30949c. Added rel="noopener noreferrer" to the external GitHub Releases link to prevent reverse-tabnabbing.
.github/release-drafter.yml
Outdated
|
|
||
| --- | ||
|
|
||
| **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...$RESOLVED_VERSION |
There was a problem hiding this comment.
The “Full Changelog” link ends with ...$RESOLVED_VERSION, but your tags are v$RESOLVED_VERSION (per tag-template). As written, the compare link will likely 404. Update it to compare against v$RESOLVED_VERSION (or adjust templates) so the URL matches actual tag names.
| **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...$RESOLVED_VERSION | |
| **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION |
| - name: Set Version for release | ||
| if: github.event_name == 'workflow_dispatch' | ||
| run: | | ||
| VERSION="${{ github.event.inputs.version }}" | ||
| echo "📝 Setting version to ${VERSION}" | ||
| echo "${VERSION}" > docs/VERSION.txt | ||
| echo "Release: ${VERSION}" > docs/version.txt | ||
| echo "Date: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> docs/version.txt | ||
| echo "Commit: ${{ github.sha }}" >> docs/version.txt | ||
|
|
There was a problem hiding this comment.
This step only runs for workflow_dispatch, so tag-triggered releases will not update docs/VERSION.txt and docs/version.txt. If these files are intended to track every release, generate/update them for both tag and manual runs (using the already-computed version).
There was a problem hiding this comment.
Fixed in commit a30949c. Removed the if: github.event_name == 'workflow_dispatch' condition so VERSION.txt and version.txt are now generated for both tag-triggered and manual releases.
| - name: Deploy to GitHub Pages | ||
| uses: JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4.8.0 | ||
| with: | ||
| folder: . | ||
| target-folder: . | ||
| branch: gh-pages | ||
| clean: false | ||
| commit-message: "chore(release): deploy version ${{ needs.prepare.outputs.version }} to gh-pages" |
There was a problem hiding this comment.
The Pages deploy step publishes the checked-out master workspace (folder: .), not the built/minified release output from the build job. This means the “backup” site can diverge from the release artifact. Consider deploying an extracted build artifact (unzip into a staging dir) or re-running the same build/minify in this job and deploying that folder.
There was a problem hiding this comment.
Fixed in commit a30949c. Added a step to extract the built release artifact and changed the deployment folder to release-deploy. The gh-pages site now deploys the minified release artifact instead of the master workspace, ensuring consistency with the release package.
docs/README.md
Outdated
|
|
||
| The release workflow automatically generates and commits the following documentation: | ||
|
|
||
| - **lighthouse-report.html** - Performance, accessibility, best practices, and SEO audit |
There was a problem hiding this comment.
The README lists lighthouse-report.html, but the workflow copies docs/lighthouse-*.html and also creates docs/lighthouse-summary.html. Update this to match the actual generated filenames so users can find the reports.
| - **lighthouse-report.html** - Performance, accessibility, best practices, and SEO audit | |
| - **lighthouse-*.html** - Individual Lighthouse reports for each audited page (performance, accessibility, best practices, and SEO) | |
| - **lighthouse-summary.html** - Aggregated Lighthouse summary report across all audited pages |
There was a problem hiding this comment.
Fixed in commit a30949c. Updated docs/README.md to match actual generated filenames: lighthouse-*.html for individual reports and lighthouse-summary.html for the aggregated summary.
docs/README.md
Outdated
| The release workflow automatically generates and commits the following documentation: | ||
|
|
||
| - **lighthouse-report.html** - Performance, accessibility, best practices, and SEO audit | ||
| - **html-validation.txt** - HTML validation results for all pages | ||
| - **accessibility-report.html** - WCAG 2.1 AA compliance verification | ||
| - **security-report.html** - OWASP ZAP security scan results | ||
| - **SBOM files** - Software Bill of Materials in SPDX format | ||
| - **Attestation files** - Build provenance and SBOM attestations | ||
|
|
||
| ## Documentation as Code | ||
|
|
||
| All documentation is: | ||
| - ✅ Automatically generated during release | ||
| - ✅ Committed to the repository | ||
| - ✅ Versioned alongside code | ||
| - ✅ Available in GitHub Releases |
There was a problem hiding this comment.
This README implies SBOM/attestation files are generated and committed into docs/, but the workflow generates them as release artifacts (uploaded/attached to the GitHub Release) rather than committing them under docs/. Clarify whether they should live in docs/ or adjust the text to point to the release assets instead.
| The release workflow automatically generates and commits the following documentation: | |
| - **lighthouse-report.html** - Performance, accessibility, best practices, and SEO audit | |
| - **html-validation.txt** - HTML validation results for all pages | |
| - **accessibility-report.html** - WCAG 2.1 AA compliance verification | |
| - **security-report.html** - OWASP ZAP security scan results | |
| - **SBOM files** - Software Bill of Materials in SPDX format | |
| - **Attestation files** - Build provenance and SBOM attestations | |
| ## Documentation as Code | |
| All documentation is: | |
| - ✅ Automatically generated during release | |
| - ✅ Committed to the repository | |
| - ✅ Versioned alongside code | |
| - ✅ Available in GitHub Releases | |
| The release workflow automatically generates the following documentation and reports: | |
| - **lighthouse-report.html** - Performance, accessibility, best practices, and SEO audit | |
| - **html-validation.txt** - HTML validation results for all pages | |
| - **accessibility-report.html** - WCAG 2.1 AA compliance verification | |
| - **security-report.html** - OWASP ZAP security scan results | |
| - **SBOM files** - Software Bill of Materials in SPDX format, published as GitHub Release assets | |
| - **Attestation files** - Build provenance and SBOM attestations, published as GitHub Release assets | |
| ## Documentation as Code | |
| Generated documentation and reports are: | |
| - ✅ Automatically generated during release | |
| - ✅ HTML and validation reports are committed to the repository | |
| - ✅ Committed reports are versioned alongside code | |
| - ✅ SBOM and attestation files are available as assets in each GitHub Release |
There was a problem hiding this comment.
Fixed in commit a30949c. Updated docs/README.md to clarify that SBOM and attestation files are published as GitHub Release assets, not committed to the docs/ directory. The README now clearly distinguishes between HTML/validation reports (committed to repo) and SBOM/attestations (attached to releases).
|
@copilot apply changes based on the comments in this thread also look at https://github.com/Hack23/homepage/actions/runs/22122529843/job/63946000779?pr=1060 |
…release from tags, fix artifact names, improve deployment Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
…ensive release documentation badges Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
…tations and documentation as code Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
…and adjust roadmap Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
…tions and release workflow security controls Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
…ement status Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
.github/workflows/release.yml
Outdated
|
|
||
| **Release Date:** $(date -u '+%Y-%m-%d %H:%M:%S UTC') | ||
| **Commit:** \`${{ github.sha }}\` | ||
| **Pre-release:** ${{ needs.prepare.outputs.is_prerelease }} |
There was a problem hiding this comment.
needs.prepare.outputs.is_prerelease is referenced while still inside the prepare job. The needs context is not available in the same job and will cause an expression evaluation error. Use the already-resolved version (and/or the workflow_dispatch input) to compute the pre-release flag within this step, or expose it as a step output and reference that instead.
| **Pre-release:** ${{ needs.prepare.outputs.is_prerelease }} | |
| **Pre-release:** ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.prerelease == 'true' && 'true' || 'false' }} |
There was a problem hiding this comment.
Fixed in commit 135cbd4. Changed to compute pre-release status directly within the step instead of referencing needs.prepare.outputs (which isn't available in the same job). Now uses: github.event_name == 'workflow_dispatch' && github.event.inputs.prerelease == 'true' || contains(steps.get-version.outputs.version, '-')
| else | ||
| VERSION=${{ github.event.inputs.version }} | ||
| fi | ||
| echo "version=${VERSION}" >> $GITHUB_OUTPUT |
There was a problem hiding this comment.
The workflow_dispatch version input is used directly as a tag/ref name and embedded into filenames without any validation. This allows invalid tag names (or unexpected characters) to break the workflow or create surprising tags/artifacts. Add a strict format validation (e.g., ^v\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$) and fail fast if the input/tag does not match.
| echo "version=${VERSION}" >> $GITHUB_OUTPUT | |
| # Enforce strict version format: vX.Y.Z or vX.Y.Z-<prerelease> | |
| if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z\.-]+)?$ ]]; then | |
| echo "Error: Invalid version '$VERSION'. Expected format 'vX.Y.Z' or 'vX.Y.Z-<prerelease>'." >&2 | |
| exit 1 | |
| fi | |
| echo "version=${VERSION}" >> "$GITHUB_OUTPUT" |
There was a problem hiding this comment.
Fixed in commit 135cbd4. Added strict version format validation with regex ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z\.-]+)?$ that fails fast with a clear error message if the version format is invalid.
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| fetch-depth: 0 | ||
| ref: ${{ github.event.repository.default_branch }} |
There was a problem hiding this comment.
On tag-triggered releases, the workflow checks out the default branch (ref: github.event.repository.default_branch) before generating HTML validation reports and writing docs/version.txt. This can make the generated documentation reflect a different commit than the tag being released (even though the version is derived from the tag). Consider generating docs from the tag/SHA being released, and then switching to the default branch only for committing/pushing the generated docs/ updates.
| ref: ${{ github.event.repository.default_branch }} | |
| ref: ${{ github.ref }} |
| - name: Set Version for release | ||
| run: | | ||
| VERSION="${{ steps.get-version.outputs.version }}" | ||
| echo "📝 Setting version to ${VERSION}" | ||
| echo "${VERSION}" > docs/VERSION.txt | ||
| echo "Release: ${VERSION}" > docs/version.txt | ||
| echo "Date: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> docs/version.txt | ||
| echo "Commit: ${{ github.sha }}" >> docs/version.txt |
There was a problem hiding this comment.
Set Version for release writes to docs/VERSION.txt and docs/version.txt before the workflow ensures docs/ exists (mkdir -p docs happens in the following step). This will fail if the directory is missing (e.g., first run or if the folder gets removed/renamed). Create/ensure the directory exists before writing these files (or move mkdir -p docs earlier).
There was a problem hiding this comment.
Fixed in commit 135cbd4. Moved mkdir -p docs to run before writing VERSION.txt and version.txt files to ensure the directory exists for first run or if folder was removed.
docs/WORKFLOW_DOCUMENTATION.md
Outdated
| ``` | ||
| docs/ | ||
| ├── index.html # Documentation viewer | ||
| ├── README.md # This file |
There was a problem hiding this comment.
In the docs/ tree example, README.md is labeled as “This file”, but this document is docs/WORKFLOW_DOCUMENTATION.md. This is confusing for readers trying to find the right entrypoint; update the comment to point at the correct file (or adjust the tree to include WORKFLOW_DOCUMENTATION.md).
| ├── README.md # This file | |
| ├── README.md # Documentation overview | |
| ├── WORKFLOW_DOCUMENTATION.md # This file |
There was a problem hiding this comment.
Fixed in commit 135cbd4. Updated the docs tree to include WORKFLOW_DOCUMENTATION.md with "This file" comment pointing to the correct file.
SECURITY_ARCHITECTURE.md
Outdated
| uses: anchore/sbom-action@22f5bcb07eeea30e5ba0ab7ce8bd0eebba62b01e # v0.22.2 | ||
| with: | ||
| format: spdx-json | ||
| output-file: homepage-${{ needs.prepare.outputs.version }}.spdx.json | ||
|
|
||
| - name: Generate SBOM attestation | ||
| uses: actions/attest-sbom@33e1d7e6f6db73291f59e53e5a08bfc29cf0e6bd # v3.0.0 |
There was a problem hiding this comment.
The pinned action SHAs shown as “Implemented in release.yml” don’t match the actual pinned SHAs in .github/workflows/release.yml (e.g., anchore/sbom-action and actions/attest-sbom). Since this section is used as implementation evidence, it should be kept in sync with the workflow (or reference only the version, not a specific SHA, if you don’t want to track SHA churn in docs).
| uses: anchore/sbom-action@22f5bcb07eeea30e5ba0ab7ce8bd0eebba62b01e # v0.22.2 | |
| with: | |
| format: spdx-json | |
| output-file: homepage-${{ needs.prepare.outputs.version }}.spdx.json | |
| - name: Generate SBOM attestation | |
| uses: actions/attest-sbom@33e1d7e6f6db73291f59e53e5a08bfc29cf0e6bd # v3.0.0 | |
| uses: anchore/sbom-action@v0.22.2 | |
| with: | |
| format: spdx-json | |
| output-file: homepage-${{ needs.prepare.outputs.version }}.spdx.json | |
| - name: Generate SBOM attestation | |
| uses: actions/attest-sbom@v3.0.0 |
There was a problem hiding this comment.
Fixed in commit 135cbd4. Removed specific SHA pins from SECURITY_ARCHITECTURE.md code examples, now showing only version tags (v0.22.2, v3.0.0) to avoid documentation churn while the actual workflow maintains SHA-pinned versions for security.
SECURITY_ARCHITECTURE.md
Outdated
| | **Provenance Available** | Cryptographic attestation generated | `homepage-vX.Y.Z.zip.intoto.jsonl` | | ||
| | **Provenance Authenticated** | GitHub OIDC signing (non-falsifiable) | `actions/attest-build-provenance@v3.2.0` | | ||
| | **Isolated** | Ephemeral GitHub-hosted runners | Workflow runs on `ubuntu-latest` | | ||
| | **Parameterless** | Reproducible builds, no external input | Version from tags, no manual params | |
There was a problem hiding this comment.
The SLSA “Parameterless” row claims there are no manual parameters (“Version from tags, no manual params”), but the workflow supports workflow_dispatch with user-provided version and prerelease inputs. Either qualify this statement as applying to tag-triggered releases only, or update the evidence/wording to match the current workflow behavior.
| | **Parameterless** | Reproducible builds, no external input | Version from tags, no manual params | | |
| | **Parameterless** | Reproducible tag-triggered builds, no external input for tagged releases | Tag push: version from tags; `workflow_dispatch`: manual version/prerelease inputs | |
There was a problem hiding this comment.
Fixed in commit 135cbd4. Clarified the SLSA Parameterless row to specify it applies to tag-triggered releases: "Tag push: version from tags; workflow_dispatch: manual version/prerelease inputs".
|
@copilot apply changes based on the comments in this thread 0s |
…lease reference, ensure docs directory exists, update documentation Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
The labeler configuration error was already fixed in commit 126e78b. The Additionally, addressed all 6 review comments from the second review in commit 135cbd4:
The labeler workflow should now work correctly on the next PR. |
|




Overview
Resolves labeler workflow failure from unsupported
changed-files.countoption and updates documentation to reflect SLSA Build Level 3 release workflow implementation.Changes
Labeler Configuration Fix
changed-files.count- unsupported in actions/labeler v5+Release Documentation Badges
Added 6-badge table to README.md with dual-linking strategy:
Architecture Documentation Updates
WORKFLOWS.md (+156 lines)
FUTURE_WORKFLOWS.md
SECURITY_ARCHITECTURE.md (+95 lines)
FUTURE_SECURITY_ARCHITECTURE.md
Cross-References
All documentation now consistently links to:
Example
Before (causing CI failure):
After:
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.