Repository navigation
fix: ghcr.yml #89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: ghcr.yml #89
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -26,16 +26,79 @@ permissions: | |||||||||||||||||||||||||
| contents: read | ||||||||||||||||||||||||||
| packages: write | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||
| IMAGE: ghcr.io/${{ github.repository_owner }}/agent | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||
| publish: | ||||||||||||||||||||||||||
| name: Build and push to GHCR | ||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||
| build: | ||||||||||||||||||||||||||
| name: Build ${{ matrix.platform }} | ||||||||||||||||||||||||||
| runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-latest' || 'ubuntu-24.04-arm' }} | ||||||||||||||||||||||||||
| strategy: | ||||||||||||||||||||||||||
| fail-fast: false | ||||||||||||||||||||||||||
| matrix: | ||||||||||||||||||||||||||
| platform: [ linux/amd64, linux/arm64 ] | ||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||
| - name: Prepare arch vars | ||||||||||||||||||||||||||
| id: prep | ||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||
| ARCH="${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}" | ||||||||||||||||||||||||||
| echo "arch=$ARCH" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Checkout | ||||||||||||||||||||||||||
| uses: actions/checkout@v4 | ||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||
| ref: ${{ inputs.ref }} | ||||||||||||||||||||||||||
| fetch-depth: 0 | ||||||||||||||||||||||||||
| fetch-depth: 1 | ||||||||||||||||||||||||||
|
Comment on lines
47
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== workflow excerpt =="
sed -n '1,120p' .github/workflows/ghcr.yml 2>/dev/null || true
echo
echo "== workflow files mentioning persist-credentials / actions/checkout =="
rg -n "persist-credentials|actions/checkout@|actions/checkout:" .github/workflows || true
echo
echo "== Dockerfile candidates =="
git ls-files | rg '(^|/)Dockerfile$|(^|/).*Dockerfile.*$' || true
echo
echo "== possible COPY . patterns =="
rg -n "^\s*COPY\s+" .github/workflows || true
rg -n "^\s*Dockerfile|Dockerfile:" .github/workflows || true
echo
echo "== changed files stat =="
git diff --stat || trueRepository: Portabase/agent Length of output: 4080 🌐 Web query:
💡 Result: In actions/checkout v4, the persist-credentials input defaults to true [1][2]. When enabled, this option configures the authentication token (or SSH key) used for the checkout within the local git configuration [3][2]. This default behavior allows subsequent steps in the same job to run authenticated git commands (such as git push or git fetch) without needing to manually re-specify the token or credentials [3][4]. The action manages this by removing the token during post-job cleanup [3]. If you prefer to prevent the credentials from being added to the local git config, you can explicitly opt-out by setting persist-credentials: false in your workflow file [3][4]. Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== docker/Dockerfile excerpt =="
wc -l docker/Dockerfile
sed -n '1,220p' docker/Dockerfile
echo
echo "== search git directory handling =="
rg -n "^\s*COPY\s+(\.\s*$|\./\s*$|.*\b(\.git|dockerignore)\b)|EXCLUDE|\.gitignore|dockerignore|\.dockerignore" docker/Dockerfile ./.dockerignore .github/workflows/ghcr.yml 2>/dev/null || true
echo
echo "== repository gitignore/dockerignore candidates =="
git ls-files | rg '(^|/)(\.dockerignore|Dockerfile.*)|(^|/)(\..*ignore|.*ignore)$' || true
echo
echo "== current .git existence and action config =="
python3 - <<'PY'
from pathlib import Path
import hashlib, json
for path in [Path('.git'), Path('docker/.dockerignore')]:
print(f"{path}: exists={path.exists()} type={path.stat().st_mode if path.exists() else None}")
if Path('.git').exists():
print(".git is present in the repository root, so context: . would include it unless docker context rules ignore it.")
PYRepository: Portabase/agent Length of output: 5283 Do not persist the checkout token in the workspace.
Proposed fix - name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
+ persist-credentials: false📝 Committable suggestion
Suggested change
🧰 Tools🪛 zizmor (1.26.1)[warning] 47-51: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Set up Docker Buildx | ||||||||||||||||||||||||||
| uses: docker/setup-buildx-action@v3 | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Log in to GHCR | ||||||||||||||||||||||||||
| uses: docker/login-action@v3 | ||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||
| registry: ghcr.io | ||||||||||||||||||||||||||
| username: ${{ github.actor }} | ||||||||||||||||||||||||||
| password: ${{ secrets.GITHUB_TOKEN }} | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Build and push by digest | ||||||||||||||||||||||||||
| id: build | ||||||||||||||||||||||||||
| uses: docker/build-push-action@v6 | ||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||
| context: . | ||||||||||||||||||||||||||
| file: ${{ inputs.dockerfile }} | ||||||||||||||||||||||||||
| platforms: ${{ matrix.platform }} | ||||||||||||||||||||||||||
| target: ${{ inputs.target }} | ||||||||||||||||||||||||||
| provenance: false | ||||||||||||||||||||||||||
| outputs: type=image,name=${{ env.IMAGE }},push-by-digest=true,name-canonical=true,push=true | ||||||||||||||||||||||||||
| cache-from: type=gha,scope=ghcr-${{ steps.prep.outputs.arch }} | ||||||||||||||||||||||||||
| cache-to: type=gha,mode=max,scope=ghcr-${{ steps.prep.outputs.arch }},ignore-error=true | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Export digest | ||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||
| DIGEST: ${{ steps.build.outputs.digest }} | ||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||
| mkdir -p /tmp/digests | ||||||||||||||||||||||||||
| touch "/tmp/digests/${DIGEST#sha256:}" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Upload digest | ||||||||||||||||||||||||||
| uses: actions/upload-artifact@v4 | ||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||
| name: digest-${{ steps.prep.outputs.arch }} | ||||||||||||||||||||||||||
| path: /tmp/digests/* | ||||||||||||||||||||||||||
| if-no-files-found: error | ||||||||||||||||||||||||||
| retention-days: 1 | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| merge: | ||||||||||||||||||||||||||
| name: Create multi-arch manifest | ||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||
| needs: build | ||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||
| - name: Download digests | ||||||||||||||||||||||||||
| uses: actions/download-artifact@v4 | ||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||
| path: /tmp/digests | ||||||||||||||||||||||||||
| pattern: digest-* | ||||||||||||||||||||||||||
| merge-multiple: true | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Set up Docker Buildx | ||||||||||||||||||||||||||
| uses: docker/setup-buildx-action@v3 | ||||||||||||||||||||||||||
|
|
@@ -51,22 +114,19 @@ jobs: | |||||||||||||||||||||||||
| id: meta | ||||||||||||||||||||||||||
| uses: docker/metadata-action@v5 | ||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||
| images: ghcr.io/${{ github.repository_owner }}/agent | ||||||||||||||||||||||||||
| images: ${{ env.IMAGE }} | ||||||||||||||||||||||||||
| tags: | | ||||||||||||||||||||||||||
| type=semver,pattern={{version}},value=${{ inputs.version }} | ||||||||||||||||||||||||||
| type=semver,pattern={{major}}.{{minor}},value=${{ inputs.version }} | ||||||||||||||||||||||||||
| type=semver,pattern={{major}},value=${{ inputs.version }} | ||||||||||||||||||||||||||
| type=raw,value=latest,enable=${{ inputs.add_latest }} | ||||||||||||||||||||||||||
|
Comment on lines
118
to
122
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== workflow excerpt =="
fd -a 'ghcr\.ya?ml' .github/workflows || true
file="$(fd 'ghcr\.ya?ml' .github/workflows | head -n1 || true)"
if [ -n "$file" ]; then
wc -l "$file"
sed -n '1,180p' "$file" | cat -n
fi
echo "== search docker/metadata action usage/options =="
rg -n "metadata-action|flavor|add_latest|latest|tags:" .github/workflows
echo "== repo files likely related =="
git ls-files .github/workflows | sed -n '1,120p'Repository: Portabase/agent Length of output: 7146 🌐 Web query:
💡 Result: In the Docker Metadata Action (v5 and later), the flavor input controls how the latest tag is generated through its latest attribute, which defaults to auto [1][2]. The auto setting means the action implicitly enables a latest tag when using specific tag types that support it, provided they are not superseded by other tag types with higher priority [3][4]. The tag types that implicitly trigger this latest tag behavior include type=ref (event=tag), type=semver, type=pep440, and type=match [1][3]. If you wish to change this behavior, you can explicitly configure the latest attribute within the flavor input: - latest=true: Forces the generation of a latest tag [1]. - latest=false: Disables the generation of an implicit latest tag [3][4]. Additionally, if you are using prefixes or suffixes within the flavor input and want them to apply to the implicitly generated latest tag, you must explicitly enable this by adding,onlatest=true to the prefix or suffix definition [4]. Example configuration: flavor: | latest=auto suffix=-my-suffix,onlatest=true Citations:
🌐 Web query:
💡 Result: In the docker/metadata-action v5, setting flavor: | latest=false prevents the action from automatically generating and adding the latest tag to your output [1][2]. By default, the flavor input is set to latest=auto [3][4]. In auto mode, the action automatically generates a latest tag for specific events and tag types, including type=semver [3][5][6]. Using latest=false explicitly opts out of this behavior [5][2]. For type=semver tags specifically, the action supports patterns to generate versions from Git tags [7][8]. You can define these patterns in the tags input using Handlebars-style expressions [7]: - {{version}}: Shorthand for {{major}}.{{minor}}.{{patch}} [7] - {{major}}: Major version identifier [7] - {{minor}}: Minor version identifier [7] - {{patch}}: Patch version identifier [7] Example usage combining these features: - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: my-image tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} flavor: | latest=false This configuration will generate semver-based tags without adding an implicit latest tag [1][2]. Citations:
Disable metadata-action’s implicit
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Build and push image | ||||||||||||||||||||||||||
| uses: docker/build-push-action@v6 | ||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||
| context: . | ||||||||||||||||||||||||||
| file: ${{ inputs.dockerfile }} | ||||||||||||||||||||||||||
| platforms: linux/amd64,linux/arm64 | ||||||||||||||||||||||||||
| push: true | ||||||||||||||||||||||||||
| tags: ${{ steps.meta.outputs.tags }} | ||||||||||||||||||||||||||
| target: ${{ inputs.target }} | ||||||||||||||||||||||||||
| provenance: false | ||||||||||||||||||||||||||
| cache-from: type=gha,scope=ghcr-build | ||||||||||||||||||||||||||
| cache-to: type=gha,mode=max,scope=ghcr-build,ignore-error=true | ||||||||||||||||||||||||||
| - name: Create and push manifest list | ||||||||||||||||||||||||||
| working-directory: /tmp/digests | ||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||
| docker buildx imagetools create \ | ||||||||||||||||||||||||||
| $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | ||||||||||||||||||||||||||
| $(printf '${{ env.IMAGE }}@sha256:%s ' *) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Inspect | ||||||||||||||||||||||||||
| run: docker buildx imagetools inspect ${{ env.IMAGE }}:${{ inputs.version }} | ||||||||||||||||||||||||||
|
Comment on lines
+131
to
+132
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== workflow excerpt =="
sed -n '1,180p' .github/workflows/ghcr.yml 2>/dev/null || true
echo "== docker metadata action usages =="
rg -n "docker/metadata-action|steps\.meta\.outputs|inputs=.*version|version\b" .github/workflows/ghcr.yml .github/workflows 2>/dev/null || true
echo "== changed file context =="
git diff -- .github/workflows/ghcr.yml | sed -n '1,220p' || trueRepository: Portabase/agent Length of output: 6662 🌐 Web query:
💡 Result: In the docker/metadata-action (v5 and later), the type=semver tag configuration allows you to format version tags using a Handlebars-based pattern [1][2]. When you use the pattern={{version}} expression with a Git tag input of v1.2.3, the action normalizes the output by removing the 'v' prefix, resulting in 1.2.3 [1][3]. The version expression is a shorthand for {{major}}.{{minor}}.{{patch}} [2][4]. The following table summarizes how different patterns affect a v1.2.3 Git tag input [1][3]: | Git tag | Pattern | Output | | --- | --- | --- | | v1.2.3 | {{raw}} | v1.2.3 | | v1.2.3 | {{version}} | 1.2.3 | | v1.2.3 | {{major}}.{{minor}} | 1.2 | | v1.2.3 | v{{major}} | v1 | | v1.2.3 | {{minor}} | 2 | | v1.2.3 | {{patch}} | 3 | This behavior applies when triggered by a push tag event or when a custom value is provided via the value attribute [1][5]. Pre-release versions (e.g., v2.0.8-beta.67) are handled similarly, though they are treated as specific versions and do not always generate shorthand aliases like {{major}}.{{minor}} in the same way as stable releases due to their frequent update nature [2][4]. Citations:
Inspect the metadata-generated version, not raw input. With Proposed fix - name: Inspect
- run: docker buildx imagetools inspect ${{ env.IMAGE }}:${{ inputs.version }}
+ env:
+ VERSION: ${{ steps.meta.outputs.version }}
+ run: docker buildx imagetools inspect "${IMAGE}:${VERSION}"📝 Committable suggestion
Suggested change
🧰 Tools🪛 zizmor (1.26.1)[warning] 132-132: code injection via template expansion (template-injection): may expand into attacker-controllable code (template-injection) [error] 132-132: code injection via template expansion (template-injection): may expand into attacker-controllable code (template-injection) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: Portabase/agent
Length of output: 213
🌐 Web query:
Docker container registry repository name lowercase paths official documentation💡 Result:
In the Docker ecosystem, repository names must be lowercase [1][2]. Official technical specifications and implementation references enforce that components within a repository path must consist of lowercase alphanumeric characters, optionally separated by periods, dashes, or underscores [3][4][2]. Key technical details regarding this requirement include: - Strict Enforcement: The Docker runtime and registry tools perform validation checks (such as the regex
[a-z0-9]+(?:[._-][a-z0-9]+)*for path components) that explicitly reject uppercase letters [3][1][2]. If you attempt to use uppercase characters in a repository name, you will typically receive an error such as: invalid reference format: repository name must be lowercase [5][2]. - Scope of Constraint: This lowercase requirement applies to the repository path components (the namespace and the repository name itself) [2]. It does not apply to the hostname/domain portion of a reference, nor does it apply to image tags, which are case-sensitive and may contain uppercase letters [4][2]. - Rationale: This constraint is maintained for cross-platform compatibility, particularly to avoid conflicts on file systems that are case-insensitive, such as those often used in Windows or macOS environments [5]. References to these rules can be found in the distribution specification and the source code for Docker reference parsing [3][1][4].Citations:
🏁 Script executed:
Repository: Portabase/agent
Length of output: 6018
🏁 Script executed:
Repository: Portabase/agent
Length of output: 1015
🌐 Web query:
ghcr.io Portabase/agent repository exists💡 Result:
Yes, the ghcr.io/portabase/agent container repository exists. While the primary container image for the Portabase Agent is hosted on Docker Hub as portabase/agent [1][2], the Portabase organization also utilizes the GitHub Container Registry (ghcr.io) for other components, such as its Helm charts (e.g., ghcr.io/portabase/charts/portabase) [3] and has recently added workflows to push images to ghcr.io [4]. Documentation and internal references confirm the project uses the GitHub Container Registry for distributing components [3][5].
Citations:
Normalize
(image)to lowercase before Buildx.IMAGEresolves toghcr.io/Portabase/agent; repository path components must be lowercase, so thedocker/build-push-actionimage output can be rejected. Use a lowercased value before the Buildx step, e.g.ghcr.io/${{ github.repository_owner }}.image.🤖 Prompt for AI Agents