mirror of
https://github.com/seerr-team/seerr.git
synced 2025-12-23 15:48:12 -05:00
ci: added helm cosign verification and renovate app workflow to bump chart versions (#2064)
* ci: added helm cosign verification and renovate app workflow to bump chart versions * docs: add helm artifacts verification Signed-off-by: Ludovic Ortega <ludovic.ortega@adminafk.fr> * fix: update app id Signed-off-by: Ludovic Ortega <ludovic.ortega@adminafk.fr> * docs: add documentation link in helm chart and seerr docs Signed-off-by: Ludovic Ortega <ludovic.ortega@adminafk.fr> --------- Signed-off-by: Ludovic Ortega <ludovic.ortega@adminafk.fr> Co-authored-by: Ludovic Ortega <ludovic.ortega@adminafk.fr>
This commit is contained in:
56
.github/workflows/helm.yml
vendored
56
.github/workflows/helm.yml
vendored
@@ -55,7 +55,7 @@ jobs:
|
||||
# get current version
|
||||
current_version=$(grep '^version:' "$chart_path/Chart.yaml" | awk '{print $2}')
|
||||
# try to get current release version
|
||||
if oras manifest fetch "ghcr.io/${GITHUB_REPOSITORY@L}/${chart_name}:${current_version}" >/dev/null 2>&1; then
|
||||
if oras manifest fetch "ghcr.io/${{ github.repository }}/${chart_name}:${current_version}" >/dev/null 2>&1; then
|
||||
echo "No version change for $chart_name. Skipping."
|
||||
else
|
||||
helm dependency build "$chart_path"
|
||||
@@ -87,8 +87,8 @@ jobs:
|
||||
name: Publish to ghcr.io
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
packages: write # needed for pushing to github registry
|
||||
id-token: write # needed for signing the images with GitHub OIDC Token
|
||||
packages: write
|
||||
id-token: write
|
||||
needs: [package-helm-chart]
|
||||
if: needs.package-helm-chart.outputs.has_artifacts == 'true'
|
||||
steps:
|
||||
@@ -128,17 +128,59 @@ jobs:
|
||||
# push chart to OCI
|
||||
chart_release_file=$(basename "$chart_path")
|
||||
chart_name=${chart_release_file%-*}
|
||||
helm push ${chart_path} oci://ghcr.io/${GITHUB_REPOSITORY@L} |& tee helm-push-output.log
|
||||
helm push ${chart_path} oci://ghcr.io/${{ github.repository }} |& tee helm-push-output.log
|
||||
chart_digest=$(awk -F "[, ]+" '/Digest/{print $NF}' < helm-push-output.log)
|
||||
# sign chart
|
||||
cosign sign "ghcr.io/${GITHUB_REPOSITORY@L}/${chart_name}@${chart_digest}"
|
||||
cosign sign "ghcr.io/${{ github.repository }}/${chart_name}@${chart_digest}"
|
||||
# push artifacthub-repo.yml to OCI
|
||||
oras push \
|
||||
ghcr.io/${GITHUB_REPOSITORY@L}/${chart_name}:artifacthub.io \
|
||||
ghcr.io/${{ github.repository }}/${chart_name}:artifacthub.io \
|
||||
--config /dev/null:application/vnd.cncf.artifacthub.config.v1+yaml \
|
||||
charts/$chart_name/artifacthub-repo.yml:application/vnd.cncf.artifacthub.repository-metadata.layer.v1.yaml \
|
||||
|& tee oras-push-output.log
|
||||
artifacthub_digest=$(grep "Digest:" oras-push-output.log | awk '{print $2}')
|
||||
# sign artifacthub-repo.yml
|
||||
cosign sign "ghcr.io/${GITHUB_REPOSITORY@L}/${chart_name}:artifacthub.io@${artifacthub_digest}"
|
||||
cosign sign "ghcr.io/${{ github.repository }}/${chart_name}:artifacthub.io@${artifacthub_digest}"
|
||||
done
|
||||
|
||||
verify:
|
||||
name: Verify signatures for each chart tag
|
||||
needs: [publish]
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
|
||||
|
||||
- name: Downloads artifacts
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
name: artifacts
|
||||
path: .cr-release-packages/
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Verify signatures for each chart tag
|
||||
run: |
|
||||
for chart_path in $(find .cr-release-packages -name '*.tgz' -print); do
|
||||
chart_release_file=$(basename "$chart_path")
|
||||
chart_name=${chart_release_file%-*}
|
||||
version=${chart_release_file#$chart_name-}
|
||||
version=${version%.tgz}
|
||||
|
||||
cosign verify "ghcr.io/${{ github.repository }}/${chart_name}:${version}" \
|
||||
--certificate-identity "https://github.com/${{ github.workflow_ref }}" \
|
||||
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
|
||||
done
|
||||
|
||||
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@@ -1,3 +1,4 @@
|
||||
---
|
||||
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
||||
name: Seerr Release
|
||||
|
||||
|
||||
181
.github/workflows/renovate-helm-custom-hooks.yml
vendored
Normal file
181
.github/workflows/renovate-helm-custom-hooks.yml
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
---
|
||||
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
||||
name: Renovate Helm Hooks
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- develop
|
||||
paths:
|
||||
- 'charts/**'
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: renovate-helm-hooks-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
renovate-post-run:
|
||||
name: Renovate Bump Chart Version
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
if: github.actor == 'renovate[bot]'
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
|
||||
id: app-token
|
||||
with:
|
||||
app-id: 2138788
|
||||
private-key: ${{ secrets.APP_SEERR_HELM_PRIVATE_KEY }}
|
||||
|
||||
- name: Set up chart-testing
|
||||
uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b # v2.7.0
|
||||
|
||||
- name: Run chart-testing (list-changed)
|
||||
id: list-changed
|
||||
run: |
|
||||
changed="$(ct list-changed --target-branch ${TARGET_BRANCH})"
|
||||
if [[ -n "$changed" ]]; then
|
||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
echo "changed_list=${changed//$'\n'/ }" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
env:
|
||||
TARGET_BRANCH: ${{ github.event.repository.default_branch }}
|
||||
|
||||
- name: Bump chart version
|
||||
if: steps.list-changed.outputs.changed == 'true'
|
||||
env:
|
||||
CHART: ${{ steps.list-changed.outputs.changed_list }}
|
||||
run: |
|
||||
if [[ ! -d "${CHART}" ]]; then
|
||||
echo "${CHART} directory not found"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Extract current appVersion and chart version from Chart.yaml
|
||||
APP_VERSION=$(grep -e "^appVersion:" "$CHART/Chart.yaml" | cut -d ":" -f 2 | tr -d '[:space:]' | tr -d '"')
|
||||
CHART_VERSION=$(grep -e "^version:" "$CHART/Chart.yaml" | cut -d ":" -f 2 | tr -d '[:space:]' | tr -d '"')
|
||||
|
||||
# Extract major, minor and patch versions of appVersion
|
||||
APP_MAJOR_VERSION=$(printf '%s' "$APP_VERSION" | cut -d "." -f 1)
|
||||
APP_MINOR_VERSION=$(printf '%s' "$APP_VERSION" | cut -d "." -f 2)
|
||||
APP_PATCH_VERSION=$(printf '%s' "$APP_VERSION" | cut -d "." -f 3)
|
||||
|
||||
# Extract major, minor and patch versions of chart version
|
||||
CHART_MAJOR_VERSION=$(printf '%s' "$CHART_VERSION" | cut -d "." -f 1)
|
||||
CHART_MINOR_VERSION=$(printf '%s' "$CHART_VERSION" | cut -d "." -f 2)
|
||||
CHART_PATCH_VERSION=$(printf '%s' "$CHART_VERSION" | cut -d "." -f 3)
|
||||
|
||||
# Get previous appVersion from the base commit of the pull request
|
||||
BASE_COMMIT=$(git merge-base origin/main HEAD)
|
||||
PREV_APP_VERSION=$(git show "$BASE_COMMIT":"$CHART/Chart.yaml" | grep -e "^appVersion:" | cut -d ":" -f 2 | tr -d '[:space:]' | tr -d '"')
|
||||
|
||||
# Extract major, minor and patch versions of previous appVersion
|
||||
PREV_APP_MAJOR_VERSION=$(printf '%s' "$PREV_APP_VERSION" | cut -d "." -f 1)
|
||||
PREV_APP_MINOR_VERSION=$(printf '%s' "$PREV_APP_VERSION" | cut -d "." -f 2)
|
||||
PREV_APP_PATCH_VERSION=$(printf '%s' "$PREV_APP_VERSION" | cut -d "." -f 3)
|
||||
|
||||
# Check if the major, minor, or patch version of appVersion has changed
|
||||
if [[ "$APP_MAJOR_VERSION" != "$PREV_APP_MAJOR_VERSION" ]]; then
|
||||
# Bump major version of the chart and reset minor and patch versions to 0
|
||||
CHART_MAJOR_VERSION=$((CHART_MAJOR_VERSION+1))
|
||||
CHART_MINOR_VERSION=0
|
||||
CHART_PATCH_VERSION=0
|
||||
elif [[ "$APP_MINOR_VERSION" != "$PREV_APP_MINOR_VERSION" ]]; then
|
||||
# Bump minor version of the chart and reset patch version to 0
|
||||
CHART_MINOR_VERSION=$((CHART_MINOR_VERSION+1))
|
||||
CHART_PATCH_VERSION=0
|
||||
elif [[ "$APP_PATCH_VERSION" != "$PREV_APP_PATCH_VERSION" ]]; then
|
||||
# Bump patch version of the chart
|
||||
CHART_PATCH_VERSION=$((CHART_PATCH_VERSION+1))
|
||||
fi
|
||||
|
||||
# Update the chart version in Chart.yaml
|
||||
CHART_NEW_VERSION="${CHART_MAJOR_VERSION}.${CHART_MINOR_VERSION}.${CHART_PATCH_VERSION}"
|
||||
sed -i "s/^version:.*/version: ${CHART_NEW_VERSION}/" "$CHART/Chart.yaml"
|
||||
|
||||
- name: Ensure documentation is updated
|
||||
if: steps.list-changed.outputs.changed == 'true'
|
||||
uses: docker://jnorwood/helm-docs:v1.14.2@sha256:7e562b49ab6b1dbc50c3da8f2dd6ffa8a5c6bba327b1c6335cc15ce29267979c
|
||||
|
||||
- name: Commit changes
|
||||
if: steps.list-changed.outputs.changed == 'true'
|
||||
env:
|
||||
CHART: ${{ steps.list-changed.outputs.changed_list }}
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
GITHUB_HEAD_REF: ${{ github.head_ref }}
|
||||
run: |
|
||||
# Define the target directory
|
||||
TARGET_DIR="$CHART"
|
||||
|
||||
# Fetch deleted files in the target directory
|
||||
DELETED_FILES=$(git diff --diff-filter=D --name-only HEAD -- "$TARGET_DIR")
|
||||
|
||||
# Fetch added/modified files in the target directory
|
||||
MODIFIED_FILES=$(git diff --diff-filter=ACM --name-only HEAD -- "$TARGET_DIR")
|
||||
|
||||
# Create a temporary file for JSON output
|
||||
FILE_CHANGES_JSON_FILE=$(mktemp)
|
||||
|
||||
# Initialize JSON structure in the file
|
||||
echo '{ "deletions": [], "additions": [] }' > "$FILE_CHANGES_JSON_FILE"
|
||||
|
||||
# Add deletions
|
||||
for file in $DELETED_FILES; do
|
||||
jq --arg path "$file" '.deletions += [{"path": $path}]' "$FILE_CHANGES_JSON_FILE" > "$FILE_CHANGES_JSON_FILE.tmp"
|
||||
mv "$FILE_CHANGES_JSON_FILE.tmp" "$FILE_CHANGES_JSON_FILE"
|
||||
done
|
||||
|
||||
# Add additions (new or modified files)
|
||||
for file in $MODIFIED_FILES; do
|
||||
BASE64_CONTENT=$(base64 -w 0 <"$file") # Encode file content
|
||||
jq --arg path "$file" --arg content "$BASE64_CONTENT" \
|
||||
'.additions += [{"path": $path, "contents": $content}]' "$FILE_CHANGES_JSON_FILE" > "$FILE_CHANGES_JSON_FILE.tmp"
|
||||
mv "$FILE_CHANGES_JSON_FILE.tmp" "$FILE_CHANGES_JSON_FILE"
|
||||
done
|
||||
|
||||
# Create a temporary file for the final JSON payload
|
||||
JSON_PAYLOAD_FILE=$(mktemp)
|
||||
|
||||
# Construct the final JSON using jq and store it in a file
|
||||
jq -n --arg repo "$GITHUB_REPOSITORY" \
|
||||
--arg branch "$GITHUB_HEAD_REF" \
|
||||
--arg message "fix: post upgrade changes from renovate" \
|
||||
--arg expectedOid "$GITHUB_SHA" \
|
||||
--slurpfile fileChanges "$FILE_CHANGES_JSON_FILE" \
|
||||
'{
|
||||
query: "mutation ($input: CreateCommitOnBranchInput!) {
|
||||
createCommitOnBranch(input: $input) {
|
||||
commit {
|
||||
url
|
||||
}
|
||||
}
|
||||
}",
|
||||
variables: {
|
||||
input: {
|
||||
branch: {
|
||||
repositoryNameWithOwner: $repo,
|
||||
branchName: $branch
|
||||
},
|
||||
message: { headline: $message },
|
||||
fileChanges: $fileChanges[0],
|
||||
expectedHeadOid: $expectedOid
|
||||
}
|
||||
}
|
||||
}' > "$JSON_PAYLOAD_FILE"
|
||||
|
||||
# Call GitHub API
|
||||
curl https://api.github.com/graphql -f \
|
||||
-sSf -H "Authorization: Bearer $GITHUB_TOKEN" \
|
||||
--data "@$JSON_PAYLOAD_FILE"
|
||||
|
||||
# Clean up temporary files
|
||||
rm "$FILE_CHANGES_JSON_FILE" "$JSON_PAYLOAD_FILE"
|
||||
@@ -20,6 +20,10 @@ Seerr helm chart for Kubernetes
|
||||
|
||||
Kubernetes: `>=1.23.0-0`
|
||||
|
||||
## Installation
|
||||
|
||||
Refer to [https://docs.seerr.dev/getting-started/kubernetes](Seerr kubernetes documentation)
|
||||
|
||||
## Update Notes
|
||||
|
||||
### Updating to 3.0.0
|
||||
|
||||
@@ -14,11 +14,15 @@
|
||||
|
||||
{{ template "chart.requirementsSection" . }}
|
||||
|
||||
## Installation
|
||||
|
||||
Refer to [https://docs.seerr.dev/getting-started/kubernetes](Seerr kubernetes documentation)
|
||||
|
||||
## Update Notes
|
||||
|
||||
### Updating to 3.0.0
|
||||
|
||||
Nothing change we just rebranded `jellyseerr` helm-chart to `seerr` :)
|
||||
Nothing has changed; we just rebranded the `jellyseerr` Helm chart to `seerr` 🥳.
|
||||
|
||||
### Updating to 2.7.0
|
||||
|
||||
|
||||
@@ -15,6 +15,12 @@ Refer to [Configuring Databases](/extending-jellyseerr/database-config#postgresq
|
||||
An alternative Docker image is available on Docker Hub for this project. You can find it at [Docker Hub Repository Link](https://hub.docker.com/r/seerr/seerr)
|
||||
:::
|
||||
|
||||
:::info
|
||||
All official Seerr images are cryptographically signed and include a verified [Software Bill of Materials (SBOM)](https://cyclonedx.org/).
|
||||
|
||||
To confirm that the container image you are using is authentic and unmodified, please refer to the [Verifying Signed Artifacts](/using-jellyseerr/advanced/verifying-signed-artifacts#verifying-signed-images) guide.
|
||||
:::
|
||||
|
||||
## Unix (Linux, macOS)
|
||||
:::warning
|
||||
Be sure to replace `/path/to/appdata/config` in the below examples with a valid host directory path. If this volume mount is not configured correctly, your Jellyseerr settings/data will not be persisted when the container is recreated (e.g., when updating the image or rebooting your machine).
|
||||
@@ -72,11 +78,6 @@ Finally, run the container with the same parameters originally used to create th
|
||||
```bash
|
||||
docker run -d ...
|
||||
```
|
||||
:::info
|
||||
All official Seerr images are cryptographically signed and include a verified [Software Bill of Materials (SBOM)](https://cyclonedx.org/).
|
||||
|
||||
To confirm that the container image you are using is authentic and unmodified, please refer to the [Verifying Signed Artifacts](/using-jellyseerr/advanced/verifying-signed-artifacts) guide.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
You may alternatively use a third-party updating mechanism, such as [Watchtower](https://github.com/containrrr/watchtower) or [Ouroboros](https://github.com/pyouroboros/ouroboros), to keep Jellyseerr up-to-date automatically.
|
||||
|
||||
@@ -8,6 +8,12 @@ sidebar_position: 5
|
||||
This method is not recommended for most users. It is intended for advanced users who are using Kubernetes.
|
||||
:::
|
||||
|
||||
:::info
|
||||
All official Seerr charts are cryptographically signed and include a verified [Software Bill of Materials (SBOM)](https://cyclonedx.org/).
|
||||
|
||||
To confirm that the chart you are using is authentic and unmodified, please refer to the [Verifying Signed Artifacts](/using-jellyseerr/advanced/verifying-signed-artifacts#verifying-signed-helm-charts) guide.
|
||||
:::
|
||||
|
||||
## Installation
|
||||
```console
|
||||
helm install jellyseerr oci://ghcr.io/fallenbagel/jellyseerr/jellyseerr-chart
|
||||
|
||||
@@ -12,6 +12,7 @@ import TabItem from '@theme/TabItem';
|
||||
|
||||
These artifacts are cryptographically signed using [Sigstore Cosign](https://docs.sigstore.dev/quickstart/quickstart-cosign/):
|
||||
- Container images
|
||||
- Helm charts
|
||||
|
||||
This ensures that the images you pull are authentic, tamper-proof, and built by the official Seerr release pipeline.
|
||||
|
||||
@@ -27,19 +28,11 @@ You will need the following tools installed:
|
||||
|
||||
To verify images:
|
||||
|
||||
- [Docker](https://docs.docker.com/get-docker/) **or**
|
||||
- [Podman](https://podman.io/getting-started/installation) (including [Skopeo](https://github.com/containers/skopeo/blob/main/install.md))
|
||||
- [Docker](https://docs.docker.com/get-docker/) **or** [Podman](https://podman.io/getting-started/installation) (including [Skopeo](https://github.com/containers/skopeo/blob/main/install.md))
|
||||
|
||||
---
|
||||
|
||||
# Verifying Signed Images
|
||||
|
||||
All Seerr container images published to GitHub Container Registry (GHCR) are cryptographically signed using [Sigstore Cosign](https://docs.sigstore.dev/quickstart/quickstart-cosign/).
|
||||
This ensures that the images you pull are authentic, tamper-proof, and built by the official Seerr release pipeline.
|
||||
|
||||
Each image also includes a CycloneDX SBOM (Software Bill of Materials) attestation, generated with [Trivy](https://aquasecurity.github.io/trivy/), providing transparency about all dependencies included in the image.
|
||||
|
||||
---
|
||||
## Verifying Signed Images
|
||||
|
||||
### Image Locations
|
||||
|
||||
@@ -227,17 +220,6 @@ This confirms that the image was:
|
||||
|
||||
---
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
| Issue | Likely Cause | Suggested Fix |
|
||||
|-------|---------------|----------------|
|
||||
| `no matching signatures` | Incorrect digest or tag | Retrieve the digest again using Docker or Skopeo |
|
||||
| `certificate identity does not match expected` | Workflow reference changed | Ensure your `--certificate-identity` matches this documentation |
|
||||
| `cosign: command not found` | Cosign not installed | Install Cosign from the official release |
|
||||
| `certificate expired` | Old release | Verify a newer tag or digest |
|
||||
|
||||
---
|
||||
|
||||
### Example: Full Verification Flow
|
||||
|
||||
<Tabs groupId="verify-examples">
|
||||
@@ -269,6 +251,127 @@ cosign verify ghcr.io/seerr-team/seerr@"$DIGEST" \
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Verifying Signed Helm charts
|
||||
|
||||
### Helm Chart Locations
|
||||
|
||||
Official Seerr helm charts are available from:
|
||||
|
||||
- GitHub Container Registry (GHCR): `ghcr.io/seerr-team/seerr/seerr-chart/seerr-chart:<tag>`
|
||||
|
||||
You can view all available tags on the [Seerr Releases page](https://github.com/seerr-team/seerr/pkgs/container/seerr%2Fseerr-chart).
|
||||
|
||||
---
|
||||
|
||||
### Verifying a Specific Release Tag
|
||||
|
||||
Each tagged release (for example `3.0.0`) is immutable and cryptographically signed.
|
||||
Verification should always be performed using the image digest (SHA256).
|
||||
|
||||
#### Retrieve the Helm Chart Digest
|
||||
|
||||
<Tabs groupId="verify-methods">
|
||||
<TabItem value="docker" label="Docker">
|
||||
|
||||
```bash
|
||||
docker buildx imagetools inspect ghcr.io/seerr-team/seerr/seerr-chart:3.0.0 --format '{{json .Manifest.Digest}}' | tr -d '"'
|
||||
```
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="podman" label="Podman / Skopeo">
|
||||
|
||||
```bash
|
||||
skopeo inspect docker://ghcr.io/seerr-team/seerr/seerr-chart:3.0.0 --format '{{.Digest}}'
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Example output:
|
||||
|
||||
```
|
||||
sha256:abcd1234...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Verify the Helm Chart Signature
|
||||
|
||||
```bash
|
||||
cosign verify ghcr.io/seerr-team/seerr/seerr-chart@sha256:abcd1234... \
|
||||
--certificate-identity "https://github.com/seerr-team/seerr/.github/workflows/helm.yml@refs/heads/main" \
|
||||
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
|
||||
```
|
||||
|
||||
:::info Successful Verification Example
|
||||
Verification for `ghcr.io/seerr-team/seerr/seerr-chart@sha256:abcd1234...`
|
||||
|
||||
The following checks were performed:
|
||||
|
||||
- Cosign claims validated
|
||||
- Signatures verified against the transparency log
|
||||
- Certificate issued by Fulcio to the expected workflow identity
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### Expected Certificate Identity
|
||||
|
||||
The expected certificate identity for all signed Seerr images is:
|
||||
|
||||
```
|
||||
https://github.com/seerr-team/seerr/.github/workflows/helm.yml@refs/heads/main
|
||||
```
|
||||
|
||||
This confirms that the image was:
|
||||
|
||||
- Built by the official Seerr Release workflow
|
||||
- Produced from the seerr-team/seerr repository
|
||||
- Signed using GitHub’s OIDC identity via Sigstore Fulcio
|
||||
|
||||
---
|
||||
|
||||
### Example: Full Verification Flow
|
||||
|
||||
<Tabs groupId="verify-examples">
|
||||
<TabItem value="docker" label="Docker">
|
||||
|
||||
```bash
|
||||
DIGEST=$(docker buildx imagetools inspect ghcr.io/seerr-team/seerr/seerr-chart:3.0.0 --format '{{json .Manifest.Digest}}' | tr -d '"')
|
||||
|
||||
cosign verify ghcr.io/seerr-team/seerr/seerr-chart@"$DIGEST" \
|
||||
--certificate-identity-regexp "https://github.com/seerr-team/seerr/.github/workflows/helm.yml@refs/heads/main" \
|
||||
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
|
||||
|
||||
cosign verify-attestation ghcr.io/seerr-team/seerr/seerr-chart@"$DIGEST" \
|
||||
--type cyclonedx \
|
||||
--certificate-identity-regexp "https://github.com/seerr-team/seerr/.github/workflows/helm.yml@refs/heads/main" \
|
||||
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
|
||||
```
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="podman" label="Podman / Skopeo">
|
||||
|
||||
```bash
|
||||
DIGEST=$(skopeo inspect docker://ghcr.io/seerr-team/seerr/seerr-chart:3.0.0 --format '{{.Digest}}')
|
||||
|
||||
cosign verify ghcr.io/seerr-team/seerr/seerr-chart@"$DIGEST" \
|
||||
--certificate-identity-regexp "https://github.com/seerr-team/seerr/.github/workflows/helm.yml@refs/heads/main" \
|
||||
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Likely Cause | Suggested Fix |
|
||||
|-------|---------------|----------------|
|
||||
| `no matching signatures` | Incorrect digest or tag | Retrieve the digest again using Docker or Skopeo |
|
||||
| `certificate identity does not match expected` | Workflow reference changed | Ensure your `--certificate-identity` matches this documentation |
|
||||
| `cosign: command not found` | Cosign not installed | Install Cosign from the official release |
|
||||
| `certificate expired` | Old release | Verify a newer tag or digest |
|
||||
|
||||
---
|
||||
|
||||
## Further Reading
|
||||
|
||||
Reference in New Issue
Block a user