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
31 changes: 31 additions & 0 deletions .github/workflows/ci-health-tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: ci-health-tests

on:
pull_request:
paths:
- 'cmd/**'
- 'e2e/**'
- 'pkg/**'
- 'go.*'
- '.github/**'

permissions:
contents: read
Comment on lines +12 to +13

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n 'githubv4|api.github.com|GITHUB_TOKEN_PATH|TokenPath' cmd e2e pkg

Repository: kubevirt/ci-health

Length of output: 1539


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow =="
cat -n .github/workflows/ci-health-tests.yaml | sed -n '1,180p'

echo "== gh client implementation =="
cat -n pkg/gh/main.go | sed -n '1,230p'

echo "== runner options/tests and token usages =="
rg -n 'NewClient|GITHUB_TOKEN|GITHUB_TOKEN_PATH|tokenPath|TokenPath|api\.github\.com|GitHubClient|Do' pkg cmd e2e --glob '*.go'

Repository: kubevirt/ci-health

Length of output: 13997


🌐 Web query:

GitHub Actions permissions on pull_request forks GITHUB_TOKEN contents read GitHub Actions permissions documentation

💡 Result:

GitHub Actions enforces strict security boundaries for workflows triggered by pull requests from forked repositories to prevent unauthorized access to sensitive resources [1][2][3]. Standard pull request events (such as pull_request and pull_request_review) are considered untrusted when they originate from a fork [1][3]. Consequently, the GITHUB_TOKEN granted to these workflows is automatically restricted to read-only permissions, regardless of any permissions settings defined in the workflow file [4][5][6][7]. Additionally, these workflows are denied access to repository and organization secrets [1][2][8]. The pull_request_target event is the primary exception to this restriction [4][5]. Because this event runs the workflow code from the base repository's default branch—rather than the untrusted code from the fork—it is treated as trusted [1][2]. As a result, workflows using pull_request_target receive a GITHUB_TOKEN with the permissions defined in the workflow (or repository defaults) and have access to secrets [1][2][3]. Key security considerations include: 1. Permission Adjustment: For all pull request-related events on a fork, any write permissions requested in the workflow are adjusted down to read-only, unless the repository administrator has explicitly enabled the "Send write tokens to workflows from pull requests" setting (which is generally discouraged for public repositories) [9][4][5][6]. 2. Pwn Requests: Using pull_request_target while checking out the head code of a fork PR creates a "pwn request" vulnerability, where untrusted code executes with privileged access [1][10][3]. To mitigate this, actions/checkout v7 and later includes built-in protections that refuse to fetch code from fork pull requests in pull_request_target workflows unless the allow-unsafe-pr-checkout: true flag is explicitly set [10]. 3. Best Practices: It is recommended to use an unprivileged pull_request workflow to test untrusted code and report results, followed by a separate, privileged workflow_run or pull_request_target workflow (that does not check out fork code) to perform sensitive actions [3][8][11]. For further guidance, consult the official documentation on securely using pull_request_target [1][2] and managing GitHub Actions security settings [9].

Citations:


🌐 Web query:

GitHub REST API pull_request contents read required token permissions GITHUB_TOKEN fork

💡 Result:

To access pull request contents via the GitHub REST API using the GITHUB_TOKEN in a GitHub Actions workflow, the required permissions depend on whether the pull request originates from a fork and your specific security configuration [1][2][3]. Key Considerations for Forked Pull Requests: 1. Restriction for Public Forks: If a workflow is triggered by a pull request from a public fork, the GITHUB_TOKEN is automatically limited to read-only permissions by GitHub [2][3]. This restriction is enforced regardless of any explicit permissions defined in your workflow file (YAML) or repository settings [3]. 2. Permission Escalation: If your workflow requires write access for actions on pull requests from public forks, you cannot use the GITHUB_TOKEN [3]. Instead, you must use a personal access token (PAT) or a GitHub App installation access token stored as a repository secret [4][5][6]. 3. Event Context: When using the standard pull_request event, these restrictions apply to maintain security [5][7]. If you use the pull_request_target event, the GITHUB_TOKEN may be granted broader (read/write) access even for forks, but this comes with significant security risks as it may allow unreviewed code to execute with elevated permissions [2][7]. Required Permissions Configuration: To read pull request contents or metadata, your workflow should explicitly request the necessary permissions in the YAML file to follow the principle of least privilege [4][6]. For example: permissions: pull-requests: read contents: read If you fail to include these explicitly, they default to none (or read, depending on repository settings), which can cause 403 Forbidden errors when calling API endpoints [3][8][7]. You can verify the required permissions for any specific REST API endpoint by checking the X-Accepted-GitHub-Permissions header in the API response [9].

Citations:


🌐 Web query:

GitHub REST Pull Request API default token contents permission required permission contents: read

💡 Result:

To determine the permissions required for GitHub REST API pull request operations, you should consult the X-Accepted-GitHub-Permissions response header provided by the GitHub API when a request fails due to insufficient access [1][2][3]. There is no single default token content permission for all pull request operations, as requirements vary by endpoint and action [1][2][4]. Key points regarding GitHub API permissions for pull requests: 1. Dynamic Permission Discovery: The most reliable way to identify the exact permissions needed (e.g., contents=read, pull_requests=read, etc.) is to inspect the X-Accepted-GitHub-Permissions header in your API response [1][2][3]. This header provides a comma-separated list of required permissions [1]. 2. Permission Granularity: For fine-grained personal access tokens (PATs) and GitHub Apps, permissions are modular [5][6]. While pull_requests is a common permission required for managing pull request metadata, some operations—particularly those involving repository contents or specific branch interactions—may require the contents permission set to read or write [7][1]. 3. Documentation: Official documentation for each specific REST API endpoint (such as the Pulls API) lists the necessary permissions required to call that endpoint [7][8]. Always refer to the endpoint-specific documentation or the troubleshooting guide to ensure your token or app has the correct access level [1]. 4. Access Levels: Permissions generally support read, write, or admin levels [5][6]. Note that write access implicitly includes read access, and admin access implicitly includes write access [5][6]. If you are encountering a "Resource not accessible by integration" or "Resource not accessible by personal access token" error, check the specific documentation for the endpoint you are calling or verify the error header to confirm if you need to elevate your token's permissions to include contents=read or other requirements [1].

Citations:


🌐 Web query:

GitHub GraphQL API GITHUB_TOKEN permissions pull_request query search required permissions contents read

💡 Result:

To query Pull Request information using the GitHub GraphQL API within a GitHub Actions workflow using the GITHUB_TOKEN, you must configure the appropriate permissions in your workflow YAML file [1][2]. Required Permissions For standard read-only queries on pull requests (such as retrieving metadata, comments, or reviewers), you must explicitly grant the pull-requests: read permission [2][3]. If your query also requires accessing the repository's files or commit information, you should additionally grant the contents: read permission [2][3]. Configuration Example You can define these permissions at the workflow or job level: permissions: pull-requests: read contents: read Workflow Configuration 1. Permissions Context: When you specify a permissions block, any permission not explicitly listed is set to none [2]. Always ensure all necessary scopes are included [3]. 2. Default Settings: If no permissions are explicitly defined, workflows default to a restricted set [3]. While this default includes read access to many areas, it is a security best practice to explicitly declare only the permissions your job requires [1][3]. 3. Special Case (Forks): Note that GITHUB_TOKEN permissions are limited when a workflow is triggered by a pull request from a public fork; in these cases, the token is automatically downgraded to read-only access, regardless of your configured permissions [4][2]. Troubleshooting If you receive a 401 Unauthorized or 403 Forbidden error, it typically indicates that the token lacks the specific scope required for the requested data or the endpoint [5][6][7]. You can verify the required scope by checking the GitHub GraphQL API documentation for the specific object or field you are querying [5][8]. If the GITHUB_TOKEN remains insufficient for your needs, GitHub recommends using a GitHub App installation access token or a personal access token (stored as a secret) instead [1][4].

Citations:


🌐 Web query:

GitHub Actions automatic token authentication fork pull_request permissions contents read only README GitHub

💡 Result:

When a GitHub Actions workflow is triggered by a pull request from a forked repository, GitHub automatically restricts the permissions of the GITHUB_TOKEN to enhance security [1][2][3]. Key points regarding this behavior: 1. Read-Only Restriction: By default, if a workflow is triggered by a pull request from a fork, any write permissions requested in the workflow file are downgraded to read-only [4][5][6]. This applies to all pull request-related events (such as pull_request, pull_request_review, etc.) with one critical exception [4][5]. 2. The Exception (pull_request_target): The pull_request_target event is the primary exception to this rule [4][5]. Because this event runs the workflow using the code from the base repository's default branch rather than the untrusted fork's merge commit, it is considered safe to grant it full read/write permissions and access to secrets [2][3]. 3. Administrative Override: Repository administrators can change this default behavior in the repository's Actions settings [7][1]. Specifically, there is an option to "Send write tokens to workflows from pull requests." If this setting is enabled, pull requests from forks can use a GITHUB_TOKEN with write permissions [7][1][6]. 4. Security Best Practices: Because the GITHUB_TOKEN is essentially a GitHub App installation access token with permissions limited to the repository, you should always explicitly define the minimum required permissions using the permissions key in your workflow file [1][8][9]. If a workflow requires elevated privileges that the GITHUB_TOKEN cannot provide (even with administrative overrides), you should use a dedicated GitHub App or a personal access token stored as a secret [8][9].

Citations:


🌐 Web query:

GitHub GraphQL API fetch pull request files changed by file changed contents required permissions

💡 Result:

To fetch the files changed in a pull request using the GitHub GraphQL API, you use the files field on a PullRequest object [1][2]. 1. Fetching File Changes The PullRequest object contains a files field, which returns a PullRequestChangedFileConnection [1][2]. This connection allows you to paginate through the files modified in the pull request. Key fields available for each PullRequestChangedFile node include: - path: The path of the file [1][2]. - additions: The number of additions [1][2]. - deletions: The number of deletions [1][2]. - changeType: The type of change (e.g., added, modified, deleted) [1][2]. - viewerViewedState: The viewing state of the file for the current user [1][2]. Note that the GraphQL API for files is primarily intended for metadata; if you require the actual diff content or patch details, the GitHub REST API (GET /repos/{owner}/{repo}/pulls/{pull_number}/files) remains the standard approach, as it explicitly provides the patch field in the response [3][4][5]. 2. Required Permissions When using a GitHub App or fine-grained personal access token to access this data, you must ensure the following permissions are configured: - Read-only access to "Pull requests" is required [6]. - If accessing private repositories, your token or app must have sufficient repository-level read permissions (e.g., "Metadata" and "Contents" access may also be required depending on the scope of your query) [6]. - If your request fails with a 401 or similar error, it confirms that the credentials provided do not have the necessary scope to access the specific repository or pull request [6]. When configuring these permissions, always adhere to the principle of least privilege by granting only the minimum access level required for your application to function [6].

Citations:


🌐 Web query:

GitHub GraphQL pulls fields files changed first fields pull request files permission contents: read

💡 Result:

To access file information for a pull request using the GitHub GraphQL API, you must use the files connection field within the PullRequest object [1][2]. Because this field is a connection, it requires pagination [3]. Key details include: Pagination and Fields - The files field returns a PullRequestChangedFileConnection [1][2]. - When querying files, you must specify a pagination argument, such as first: n (up to a maximum of 100 nodes per request) [3][4]. - To retrieve more than the initial batch, use the pageInfo object (which provides hasNextPage and endCursor) and the after argument to request subsequent pages [1][3][4]. - Available fields on the PullRequestChangedFile object include path, additions, deletions, changeType, and viewerViewedState [1][2]. - The PullRequest object also provides a changedFiles field, which returns an integer representing the total count of files changed [1][2]. Permissions - Accessing repository data via the GraphQL API requires appropriate permissions. For GitHub Apps and personal access tokens, the "Contents" repository permission is typically required to read repository content [5]. - If you are using a GitHub Action, ensure your workflow is configured with the necessary permissions (e.g., contents: read) in its permissions block [5][6]. - If a request is made with insufficient permissions, the API will return a 401 or 403 error [5][6]. Example Query Structure { repository(owner: "OWNER", name: "REPO") { pullRequest(number: PR_NUMBER) { files(first: 100, after: "CURSOR") { nodes { path additions deletions changeType } pageInfo { hasNextPage endCursor } } } } }

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== e2e tests suite =="
cat -n e2e/tests_suite_test.go | sed -n '1,130p'

echo "== mergequeue relevant implementation =="
cat -n pkg/mergequeue/main.go | sed -n '1,230p'

echo "== run tests direct references =="
rg -n 'FetchPRTimelineItems|OpenPRsAt|MergedPRsBetween|ChatopsMergedPRsBetween|GetSupportedBranches|run tests|go test|GITHUB_TOKEN_PATH|GITHUB_TOKEN' pkg e2e --glob '*.go' --glob '*.yaml' --glob '*.yml'

Repository: kubevirt/ci-health

Length of output: 16725


Add pull-requests: read to the GitHub token permissions.

This workflow passes GITHUB_TOKEN into go test ./..., and the test suite exercises GitHub GraphQL queries against public PR metadata via shurcooL/githubv4. When permissions is set manually, only the listed permissions are granted; contents: read alone may not authorize pull request metadata reads, causing fork PR runs to fail with authorization errors. Add pull-requests: read as the minimum scope required for these tests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci-health-tests.yaml around lines 12 - 13, Add the
pull-requests: read permission alongside contents: read in the workflow’s
top-level permissions block so GITHUB_TOKEN can access pull request metadata
during the Go test suite, while preserving the existing minimal permissions.


jobs:
test:
runs-on: ubuntu-latest
container: docker.io/golang:1.26-alpine

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

being curious: how does GitHub Actions handle the rate limiting by docker? Do we need to mirror images in the long run if we get instability here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know, if it cause issues we can switch to mirror.gcr.io/library/golang:1.26-alpine which already handles the mirroring of DockerHub images for us [1].

Note that this was the image used in the previous version of the action [2].

steps:
- name: Checkout Git repository
id: checkout
uses: actions/checkout@v6

- name: Run tests
id: test
run: |
export GITHUB_TOKEN_PATH='/run/github-token'

echo -n '${{ secrets.GITHUB_TOKEN }}' >"${GITHUB_TOKEN_PATH}"

go test ./...
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ The central artifact is `output/kubevirt/kubevirt/results.json`: `badges-update.
|----------|---------|---------|
| `badges-update.yaml` | Scheduled every 3 hours | Runs `stats` for last 7 days, commits updated badges and `results.json` |
| `ci-failures.yml` | Push to `main` modifying `results.json` | Runs `ci-failures generate report`, commits updated markdown summary |
| `ci-health-tests.yml` | Pull request that modifies Go code | Runs `go test`, validates changes |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the workflow filename and trigger description.

The file is ci-health-tests.yaml, not ci-health-tests.yml; additionally, the workflow also triggers on .github/**, not only Go-code changes.

-| `ci-health-tests.yml` | Pull request that modifies Go code | Runs `go test`, validates changes |
+| `ci-health-tests.yaml` | Pull request modifying `cmd/**`, `e2e/**`, `pkg/**`, `go.*`, or `.github/**` | Runs `go test`, validates changes |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| `ci-health-tests.yml` | Pull request that modifies Go code | Runs `go test`, validates changes |
| `ci-health-tests.yaml` | Pull request modifying `cmd/**`, `e2e/**`, `pkg/**`, `go.*`, or `.github/**` | Runs `go test`, validates changes |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 143, Update the workflow table entry for
ci-health-tests.yaml: correct the filename extension from .yml to .yaml and
revise the trigger description to include changes under .github/** in addition
to Go-code modifications.

| `historical-update.yaml` | Weekly (Monday 00:10 UTC) | Runs `batch` fetch+plot for trend metrics, commits updated plots |

### Prow Postsubmit
Expand Down