Skip to content
This repository was archived by the owner on Sep 9, 2026. It is now read-only.
Closed
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
38 changes: 38 additions & 0 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: E2E Tests

on:
pull_request:
branches: [main]
workflow_dispatch: {}
Comment on lines +4 to +7

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Add workflow concurrency to avoid PR tag races.

Multiple runs for the same PR can push the same pr-<number> tag concurrently, making E2E consume nondeterministic image content.

Suggested change
 on:
   pull_request:
     branches: [main]
   workflow_dispatch: {}
+
+concurrency:
+  group: e2e-pr-${{ github.event.pull_request.number || github.run_id }}
+  cancel-in-progress: true

Also applies to: 24-24

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 4-7: insufficient job-level concurrency limits (concurrency-limits): workflow is missing concurrency setting

(concurrency-limits)

🤖 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/e2e-test.yml around lines 4 - 7, Add concurrency control
to the e2e workflow so multiple runs for the same pull request cannot push the
same pr-<number> tag at the same time. Update the workflow around the existing
on/pull_request and workflow_dispatch triggers in e2e-test.yml by adding a
concurrency group keyed to the PR number (or workflow ref for dispatch) and set
cancellation behavior appropriately. Use the workflow’s existing PR-based tag
generation path as the reference point when choosing the group key.

Source: Linters/SAST tools


jobs:
build-pr-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
image: ${{ steps.meta.outputs.image }}
steps:
- name: Checkout
uses: actions/checkout@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Disable persisted checkout credentials before running PR-controlled build steps.

Line 19 uses default checkout behavior, which persists auth credentials for later steps in the job.

Suggested change
       - name: Checkout
         uses: actions/checkout@<full_commit_sha>
+        with:
+          persist-credentials: false

As per path instructions, .github/workflows/**/*: Least privilege: minimize GITHUB_TOKEN permissions.

📝 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
uses: actions/checkout@v4
uses: actions/checkout@<full_commit_sha>
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 18-19: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 19-19: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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/e2e-test.yml at line 19, The checkout step in the e2e
workflow is leaving persisted auth credentials available to later PR-controlled
steps. Update the actions/checkout usage in the workflow to disable credential
persistence, and verify any subsequent job steps that need repo access use their
own least-privilege authentication. Use the checkout step and the e2e-test
workflow as the place to apply this change.

Sources: Path instructions, Linters/SAST tools


🔒 Security & Privacy | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

git ls-files .github/workflows/e2e-test.yml
wc -l .github/workflows/e2e-test.yml
cat -n .github/workflows/e2e-test.yml | sed -n '1,220p'

Repository: osac-project/osac-operator

Length of output: 1591


Pin both workflow refs to immutable SHAs.
actions/checkout@v4 and osac-project/osac-test-infra/.github/workflows/e2e.yml@main are mutable refs; lock both to commit SHAs to keep this workflow supply-chain safe. (Lines 19, 35)

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 18-19: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 19-19: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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/e2e-test.yml at line 19, The workflow currently uses
mutable refs for external actions and reusable workflows, so update both the
actions/checkout usage and the
osac-project/osac-test-infra/.github/workflows/e2e.yml reference to pinned
commit SHAs instead of version tags or main. Keep the change within the
.github/workflows/e2e-test.yml workflow and make sure the checkout step and the
reusable workflow call both reference immutable commits.

Sources: Path instructions, Linters/SAST tools


- name: Set image metadata
id: meta
run: |
IMAGE="ghcr.io/osac-project/osac-operator:pr-${{ github.event.pull_request.number || github.run_id }}"
echo "image=${IMAGE}" >> "$GITHUB_OUTPUT"

- name: Build and push PR image
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | podman login ghcr.io -u "${{ github.actor }}" --password-stdin
podman build -t "${{ steps.meta.outputs.image }}" -f Containerfile .
podman push "${{ steps.meta.outputs.image }}"
Comment on lines +27 to +31

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map relevant workflow files and inspect the target workflow around the referenced lines.
git ls-files .github/workflows
echo '---'
wc -l .github/workflows/e2e-test.yml
echo '---'
cat -n .github/workflows/e2e-test.yml | sed -n '1,220p'

Repository: osac-project/osac-operator

Length of output: 1781


🌐 Web query:

GitHub Actions pull_request forked pull requests GITHUB_TOKEN packages write read-only GitHub Container Registry push

💡 Result:

In GitHub Actions, pull requests coming from forks get a read-only GITHUB_TOKEN, so your workflow cannot use GITHUB_TOKEN to push to GitHub Container Registry (GHCR) with packages:write in that context. GitHub states that for pull requests from forks the GITHUB_TOKEN “will be … always read” and that “Pull requests from public forks are still considered a special case and will receive a read token regardless of these settings” [1]. What you need to write/push to GHCR with GITHUB_TOKEN 1) Use a workflow/job permissions block that includes packages: write. GitHub documents that GITHUB_TOKEN permissions are controlled via the workflow/job permissions key [2]. 2) Ensure the workflow run is in a context where the token is allowed to be write-capable (i.e., not the restricted forked-PR case described above) [1]. 3) GHCR specifically supports using GITHUB_TOKEN for container registry operations in Actions, but actual push capability is governed by the token’s packages scope/permissions and package/container access configuration [3][4]. Key security implication for forked pull_request workflows - Even if you try to request packages: write in the workflow, GitHub’s fork policy restricts the token to read-only for fork PRs (“always read” for pull requests from forks) [1]. - For non-fork contexts (e.g., push events, or PRs run in a trusted context), you can allow pushing by granting packages: write to GITHUB_TOKEN via permissions: packages: write [2] and authenticating to GHCR with secrets.GITHUB_TOKEN [4][3]. Example (works for non-fork/trusted contexts; not guaranteed for fork PRs) - Grant token scope: permissions: packages: write - Login to GHCR using the built-in token: password: ${{ secrets.GITHUB_TOKEN }} [5][4] If you must publish container images for fork PRs Because the forked-PR GITHUB_TOKEN is restricted to read [1], you generally need an alternate, trusted mechanism (for example, a separate workflow that runs on push to the base branch / manual approval) rather than directly pushing from the fork-originating pull_request job [1].

Citations:


🌐 Web query:

GitHub Actions pull_request forked pull requests GITHUB_TOKEN packages write read-only GitHub Container Registry push

💡 Result:

In GitHub Actions, behavior depends on (a) whether the workflow runs on a pull_request from a fork vs from the same repo, and (b) the permissions you request for GITHUB_TOKEN. 1) What GITHUB_TOKEN can do on forked pull_request events - GitHub has a special rule for pull requests from forks: the GITHUB_TOKEN is provided with read-only permissions (and no secrets access) even if your workflow/job requests broader permissions in most cases. This is explicitly called out in GitHub’s docs for “Run workflows from fork pull requests”, which states it uses a GITHUB_TOKEN with read-only permission and no access to secrets.[1] - GitHub also states that pull requests from public forks are treated as a special case and will receive a read token regardless of the permissions settings you specify in workflow/job scope.[2] Net effect for your query: If your workflow is triggered by pull_request from a fork, you should assume GITHUB_TOKEN will be read-only for scopes like packages (and other write scopes), so attempts to push to GHCR will fail unless you use an alternative trusted execution model. 2) Can you push to GitHub Container Registry (GHCR) with GITHUB_TOKEN? - GHCR / GitHub Packages support using GITHUB_TOKEN for container registry operations. GitHub’s changelog notes that you can authenticate to the Packages Container registry with GITHUB_TOKEN in Actions workflows, and that it supports reading/creating/updating/deleting containers.[3] - For package/container registry actions, GitHub Packages permissions correspond to scopes like read:packages and write:packages.[4] So: pushing to GHCR with GITHUB_TOKEN is supported when the workflow’s GITHUB_TOKEN actually has write:packages (and the workflow is allowed to obtain write permissions). 3) Why forked pull_request workflows often can’t push, even if you set permissions - If you request permissions in the workflow YAML (for example packages: write) but the event is a pull_request coming from a fork, GitHub’s special-case handling means the token still ends up read-only.[2] - Additionally, GitHub documents that the “fork pull requests” policy mode (run workflows from fork pull requests) uses a GITHUB_TOKEN with read-only permission and no secrets, which prevents privileged operations such as pushing images.[1] 4) Recommended pattern: separate build (untrusted fork) from publish (trusted) - To safely build PR code from forks but still publish artifacts (like pushing to GHCR), the typical approach is: a) Run a pull_request workflow on forks with read-only permissions to build/test (no publishing). b) Use a separate trusted trigger (for example push to main, workflow_dispatch, or a protected internal job) to publish using a token that can be granted write access. - If you instead use pull_request_target to get a token with write permissions, be aware this can run with more privilege and can be dangerous if it checks out untrusted code; this is widely considered a security anti-pattern unless done very carefully. 5) How to check/set the exact token permissions - You can set the default permissions for GITHUB_TOKEN at repository settings (“Workflow permissions”). GitHub documents that the default/restricted setting can be “read access for contents and packages”.[1] - You can also set explicit permissions in workflow/job YAML using the permissions key, including packages: read/write and pull-requests: read/write, etc. But remember that fork pull requests are still treated specially and will receive a read token.[2] Practical takeaway for your exact query keywords - “pull_request forked pull requests” + “GITHUB_TOKEN packages write” + “GHCR push”: generally will not work with pull_request from forks, because GitHub issues a read-only GITHUB_TOKEN for fork pull_request runs.[1][2] - “GITHUB_TOKEN packages read-only” works for fork PRs (pull/build/use), because read scopes are allowed.[1] - “push to GHCR” requires write:packages on GITHUB_TOKEN, which you can get in trusted workflows/events, and GitHub Packages supports using GITHUB_TOKEN for container operations.[3][4] If you share your workflow YAML (especially the trigger and permissions block) and whether the images should be pushed for public forks or only for internal contributors, I can suggest a safe configuration that matches what you’re trying to do.

Citations:


Guard the GHCR push on forked PRs

.github/workflows/e2e-test.yml:27-31 — pull_request runs from forks get a read-only GITHUB_TOKEN, so podman push will fail for external contributors. Skip this step for forks or move image publishing to a trusted workflow path.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 29-29: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 29-29: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[info] 30-30: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[info] 31-31: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 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/e2e-test.yml around lines 27 - 31, The “Build and push PR
image” step in the e2e workflow should not run for forked pull_request events
because the available GITHUB_TOKEN is read-only there. Update the workflow
around the image build/push block to either conditionally skip podman push when
the PR comes from a fork, or move the publishing logic to a trusted path; use
the existing job/step context and the build-and-push step name to locate the
change.


e2e:
needs: build-pr-image
uses: osac-project/osac-test-infra/.github/workflows/e2e.yml@main
with:
component-image: ${{ needs.build-pr-image.outputs.image }}
component-image-name: ghcr.io/osac-project/osac-operator
Comment on lines +9 to +38

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Add/attach SAST and SCA gating before this image is consumed.

The workflow currently builds/pushes and triggers E2E without an in-pipeline static/dependency security gate.

As per path instructions, .github/workflows/**/*: SAST/SCA steps in pipeline.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 18-19: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[warning] 24-24: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[warning] 29-29: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 29-29: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[info] 30-30: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[info] 31-31: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 19-19: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 35-35: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[warning] 14-14: permissions without explanatory comments (undocumented-permissions): needs an explanatory comment

(undocumented-permissions)


[info] 10-10: workflow or action definition without a name (anonymous-definition): this job

(anonymous-definition)

🤖 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/e2e-test.yml around lines 9 - 38, Add a security gate to
the workflow before the built image is handed off to the e2e job. Update the
existing build-pr-image job in the workflow to run SAST and SCA checks as
pipeline steps after Checkout and before Build and push PR image, and make the
e2e job depend on those checks passing. Use the existing job names
build-pr-image and e2e so the image is only pushed/consumed when the security
scans succeed.

Source: Path instructions

Comment on lines +27 to +38

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Workflow file map =="
git ls-files '.github/workflows/*'

echo
echo "== e2e-test workflow (line numbered) =="
cat -n .github/workflows/e2e-test.yml

echo
echo "== Search for cosign/signing/provenance in workflows =="
rg -n --hidden -S 'cosign|sigstore|provenance|attest|sign' .github/workflows . || true

echo
echo "== Search for GHCR / image signing references =="
rg -n --hidden -S 'ghcr.io|podman build|podman push|image:' .github/workflows . || true

Repository: osac-project/osac-operator

Length of output: 50383


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Workflow file map =="
git ls-files '.github/workflows/*'

echo
echo "== e2e-test workflow (line numbered) =="
cat -n .github/workflows/e2e-test.yml

echo
echo "== Search for cosign/signing/provenance in workflows =="
rg -n --hidden -S 'cosign|sigstore|provenance|attest|sign' .github/workflows . || true

echo
echo "== Search for GHCR / image signing references =="
rg -n --hidden -S 'ghcr.io|podman build|podman push|image:' .github/workflows . || true

Repository: osac-project/osac-operator

Length of output: 50383


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Workflow file map =="
git ls-files '.github/workflows/*'

echo
echo "== e2e-test workflow (line numbered) =="
cat -n .github/workflows/e2e-test.yml

echo
echo "== Search for cosign/signing/provenance in workflows =="
rg -n --hidden -S 'cosign|sigstore|provenance|attest|sign' .github/workflows . || true

echo
echo "== Search for GHCR / image signing references =="
rg -n --hidden -S 'ghcr.io|podman build|podman push|image:' .github/workflows . || true

Repository: osac-project/osac-operator

Length of output: 50383


🏁 Script executed:

#!/bin/bash
set -euo pipefail

cat -n .github/workflows/e2e-test.yml
rg -n --hidden -S 'cosign|sigstore|provenance|attest|sign' .github/workflows . || true

Repository: osac-project/osac-operator

Length of output: 50383


Sign the PR image before E2E handoff
In .github/workflows/e2e-test.yml, build-pr-image pushes straight to GHCR and e2e consumes that tag with no Sigstore/cosign step. Add signing, or have the downstream workflow verify a signed digest before use.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 29-29: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 29-29: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[info] 30-30: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[info] 31-31: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 35-35: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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/e2e-test.yml around lines 27 - 38, The build-and-push flow
in e2e-test.yml publishes the PR image to GHCR without any signing, so add a
cosign/Sigstore signing step in the build-pr-image job after podman push and
before e2e handoff. Use the existing image output from steps.meta.outputs.image
and ensure the downstream e2e workflow consumes or verifies the signed digest
rather than an unsigned tag.

Source: Path instructions

Loading