Files
core/.github/workflows/check-requirements.md
T
2026-05-20 17:59:20 +02:00

11 KiB

on, permissions, network, tools, safe-outputs, concurrency, steps, post-steps, description
on permissions network tools safe-outputs concurrency steps post-steps description
workflow_run
workflows types
Check requirements (deterministic)
completed
contents actions issues pull-requests
read read read read
allowed
python
web-fetch github
toolsets min-integrity
default
actions
unapproved
add-comment
max target
1 ${{ env.PR_NUMBER }}
group cancel-in-progress
${{ github.workflow }}-${{ github.event.workflow_run.head_sha }} true
name if uses with
Download deterministic-results artifact github.event.workflow_run.conclusion == 'success' actions/download-artifact@3e5f45b2cf
name path run-id github-token
check-requirements-deterministic /tmp/gh-aw/deterministic ${{ github.event.workflow_run.id }} ${{ secrets.GITHUB_TOKEN }}
name if run
Extract PR number from artifact github.event.workflow_run.conclusion == 'success' PR=$(python3 -c 'import json,sys;print(json.load(open("/tmp/gh-aw/deterministic/results.json"))["pr_number"])') echo "PR_NUMBER=${PR}" >> "${GITHUB_ENV}"
name if run
Verify agent produced an add_comment safe-output always() && github.event.workflow_run.conclusion == 'success' OUTPUT=/tmp/gh-aw/agent_output.json if [ ! -f "${OUTPUT}" ]; then echo "::error::Agent output file ${OUTPUT} is missing; the agent did not run to completion." exit 1 fi if ! grep -q '"add_comment"' "${OUTPUT}"; then echo "::error::Agent did not emit an add_comment safe-output; no review comment was posted to the PR." echo "Agent output:" cat "${OUTPUT}" exit 1 fi
Resolves the deterministic-stage artifact's NEEDS_AGENT checks for changed Python package requirements on PRs targeting the core repo, then posts the final review comment. Triggered by completion of the deterministic workflow. Reads the uploaded artifact from disk, replaces placeholders for any check whose status is `needs_agent`, and posts the merged comment using the PR number recorded inside the artifact itself. Each check kind has a dedicated instruction section below; if the artifact contains a check kind that does not have a section here, the agent fails hard rather than guess.

Check requirements (AW)

You are a code review assistant for the Home Assistant project. The deterministic stage has already evaluated every check it can on its own and produced an artifact containing the PR number, per-package check results, and a pre-rendered comment with placeholders. Your only job is to read that artifact, resolve any needs_agent checks, and post the final comment.

Step 1 — Read the deterministic-stage artifact

The deterministic stage uploaded its results to the runner at /tmp/gh-aw/deterministic/results.json.

The JSON has this shape:

  • pr_number — the PR being checked. The add_comment safe-output is already targeted at this PR (the workflow extracted pr_number from the artifact and wired it into the safe-output config), so you do not need to set item_number yourself — just emit add_comment with the rendered body.
  • needs_agenttrue iff any package's check needs resolution.
  • packages[] — one entry per changed package. Each entry has:
    • name, old_version (null for a newly added package; otherwise the previous pin), new_version, repo_url, publisher_kind.
    • checks — a dict keyed by check kind (string). Each value has a status (pass, warn, fail, or needs_agent) and details.
  • rendered_comment — the final PR comment body, already rendered. For every check whose status is needs_agent it contains two placeholders you must replace:
    • {{CHECK_CELL:<pkg-name>:<check-kind>}} — one cell of the summary table. Replace with exactly one of , ⚠️, .
    • {{CHECK_DETAIL:<pkg-name>:<check-kind>}} — the body of one bullet in the package's <details> block. Replace with <icon> <one-line explanation> (the bullet's leading - **<label>**: is already rendered — replace only the placeholder).

You must not modify any other content in rendered_comment. Do not re-evaluate checks that already have a deterministic status. Do not add or remove packages.

Step 2 — Resolve each needs_agent check

For each package in packages:

For each (check_kind, result) in package.checks where result.status == "needs_agent":

  1. Look up ## Check kind: <check_kind> in the Check instructions section below.

  2. If no matching section exists: emit a single add_comment whose body is:

    <!-- requirements-check -->
    ## Check requirements
    
    ❌ Internal error: the deterministic artifact contains a check kind
    (`<check_kind>` on package `<pkg-name>`) that this workflow has no
    instructions for. Update `.github/workflows/check-requirements.md`
    to add a matching `## Check kind: <check_kind>` section, or remove
    the kind from the deterministic stage.
    

    Then stop. Do not improvise a verdict for an unknown check kind.

  3. Otherwise, follow the instructions in that section. They tell you which icon (/⚠️/) and one-line explanation to produce.

Step 3 — Post the comment

  1. Replace every {{CHECK_CELL:…}} and {{CHECK_DETAIL:…}} placeholder in rendered_comment with the resolved value.
  2. Emit the resulting markdown using add_comment — set body to the merged rendered_comment verbatim (the leading <!-- requirements-check --> marker must be preserved). The PR target is already set by the workflow; do not pass item_number.

If the artifact's top-level needs_agent is false (no checks need you), emit rendered_comment unchanged.

Check instructions

Check kind: repo_public

Verify that the package's source repository is publicly reachable.

  1. Read package.repo_url.
  2. Use the web-fetch tool to GET that URL.
  3. Decide the verdict:
    • HTTP 200, returns a public repository page → <repo_url> is publicly accessible.
    • HTTP 4xx/5xx, or the response redirects to a login / sign-in page → Source repository at <repo_url> is not publicly accessible. Home Assistant requires all dependencies to have publicly available source code.
    • Any other inconclusive result → ⚠️ with a one-line description.

If repo_public resolves to for a package, also mark that package's release_pipeline cell/detail as (em dash) and explain Skipped because the source repository is not publicly accessible. — because the release pipeline cannot be inspected without a public repo.

Verify the PR description contains the right link for the change.

  1. Fetch the PR body via the GitHub MCP tool, using the pr_number field from the artifact.
  2. Extract all URLs from the body.
  3. For a new package (package.old_version is null):
    • The PR body must contain a URL that points at package.repo_url (any sub-path of the same owner/repo on the same host is acceptable). A PyPI link is not sufficient.
    • if such a URL is present.
    • otherwise: PR description must link to the source repository at <repo_url>. A PyPI page link is not sufficient.
  4. For a version bump (package.old_version is not null):
    • The PR body must contain a URL on the same host as package.repo_url that references both package.old_version and package.new_version (e.g. a GitHub compare URL compare/vX...vY, a release / changelog URL containing both versions, etc.).
    • if such a URL is present and the versions match the actual bump.
    • otherwise: PR description should link to a changelog or compare URL on <repo_url> that mentions both <old_version> and <new_version>.

Check kind: release_pipeline

Inspect the upstream project's release / publish CI pipeline.

For each package needing inspection, determine the source repository host from package.repo_url, then apply the corresponding checklist.

GitHub repositories (github.com)

  1. List workflows: GET /repos/{owner}/{repo}/actions/workflows.
  2. Identify any workflow whose name or filename suggests publishing to PyPI (release, publish, pypi, or deploy).
  3. Fetch the workflow file and check:
    • Trigger sanity: triggered by push to tags, release: published, or workflow_run on a release job — not solely workflow_dispatch with no environment-protection guard.
    • OIDC / Trusted Publisher: look for id-token: write and one of pypa/gh-action-pypi-publish, actions/attest-build-provenance, or TWINE_PASSWORD from a static secrets.PYPI_TOKEN.
    • No manual upload bypass: no ungated twine upload or pip upload.
  4. Verdict:
    • if OIDC + sane triggers + no bypass.
    • ⚠️ if static token but version bump, or details unclear.
    • if static token on a new package, or only-manual triggers with no environment protection.

GitLab repositories (gitlab.com or self-hosted GitLab)

  1. Resolve the project ID via GET https://gitlab.com/api/v4/projects/{url-encoded-namespace-and-name}.
  2. Fetch .gitlab-ci.yml via GET https://gitlab.com/api/v4/projects/{id}/repository/files/.gitlab-ci.yml/raw?ref=HEAD.
  3. Apply the same conceptual checks: tag-only / protected-branch triggers, GitLab OIDC id_tokens or CI/CD protected PYPI_TOKEN, no ungated twine upload. Same verdict rules as GitHub.

Other code hosting providers (Bitbucket, Codeberg, Gitea, Sourcehut, …)

  1. Use web-fetch to retrieve any visible CI configuration (.circleci/config.yml, Jenkinsfile, azure-pipelines.yml, bitbucket-pipelines.yml, .builds/*.yml).
  2. Apply the conceptual checks: automated triggers, CI-injected credentials, no manual twine upload.
  3. If no CI config can be retrieved: ⚠️ Release pipeline could not be inspected; hosting provider is not GitHub or GitLab.

Notes

  • Be constructive and helpful. Reference the inspected workflow / CI file by URL where useful so the contributor can fix the issue.
  • The dedup of the requirements-check comment is handled by gh-aw's add_comment safe-output via the <!-- requirements-check --> marker on the first line of rendered_comment.
  • If the deterministic workflow concluded with a non-success status, this workflow's if: guard on Download deterministic-results artifact skipped the download. If you find no file at /tmp/gh-aw/deterministic/results.json, emit nothing — the post-step verification is also gated and will not complain.