-
Notifications
You must be signed in to change notification settings - Fork 1
feat(web): task-centric redesign — enclosed shell, full-page settings, multi-project task tree #82
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
Changes from all commits
3b04171
828f7fe
a9da92f
1b1c247
b855de1
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 |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| name: CI | ||
|
|
||
| # Quality gate: runs on every push to main and on pull requests so regressions | ||
| # are caught before they reach a release tag. | ||
| on: | ||
| push: | ||
| branches: [main] | ||
| pull_request: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: ci-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| go: | ||
| name: Go (build · vet · test · lint) | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v5 | ||
| with: | ||
| # Full history so golangci-lint's only-new-issues can diff against base. | ||
| fetch-depth: 0 | ||
|
|
||
| - uses: actions/setup-go@v6 | ||
| with: | ||
| go-version-file: 'go.mod' | ||
|
|
||
| # build-web (vite) is needed because internal/web embeds dist/* via | ||
| # //go:embed — without it the whole module fails to compile. | ||
| - uses: actions/setup-node@v5 | ||
| with: | ||
| node-version: '22' | ||
| - name: Install pnpm | ||
| run: npm install -g pnpm | ||
|
|
||
| # registry_generated.go + the theme TS/CSS are generated (gitignored), and | ||
| # internal/web/dist must exist for the go:embed. `make generate build-web` | ||
| # produces all three. model generate fetches models.dev; theme is offline. | ||
| - name: Generate code + build frontend | ||
| run: make generate build-web | ||
|
|
||
| - name: Build | ||
| run: go build ./... | ||
|
|
||
| - name: Vet | ||
| run: go vet ./... | ||
|
|
||
| - name: Test | ||
| run: go test ./... | ||
|
|
||
| - name: golangci-lint | ||
| uses: golangci/golangci-lint-action@v7 | ||
| with: | ||
| version: latest | ||
| # Gate regressions without forcing a flag-day cleanup of the existing | ||
| # lint debt (mostly upstream adk.AgentMiddleware deprecations). New | ||
| # issues introduced by a PR still fail. | ||
| only-new-issues: true | ||
|
|
||
| web: | ||
| name: Web (type-check · build) | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v5 | ||
|
|
||
| # Go is needed only to run the theme generator, which writes | ||
| # web/src/composables/themes.generated.ts + styles/tokens.generated.css | ||
| # (gitignored) — without them vue-tsc can't resolve ./themes.generated. | ||
| - uses: actions/setup-go@v6 | ||
| with: | ||
| go-version-file: 'go.mod' | ||
|
|
||
| - uses: actions/setup-node@v5 | ||
| with: | ||
| node-version: '22' | ||
|
|
||
| - name: Install pnpm | ||
| run: npm install -g pnpm | ||
|
|
||
| - name: Generate theme assets | ||
| run: go generate ./internal/theme/... | ||
|
|
||
| - name: Install deps | ||
| working-directory: web | ||
| run: pnpm install --frozen-lockfile | ||
|
|
||
| - name: Type-check | ||
| working-directory: web | ||
| run: pnpm type-check | ||
|
|
||
| - name: Lint | ||
| working-directory: web | ||
| run: npx oxlint . | ||
|
|
||
| - name: Build | ||
| working-directory: web | ||
| run: npx vite build | ||
|
Comment on lines
+74
to
+81
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. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check for lint script in web/package.json
cat web/package.json | jq '.scripts.lint'Repository: cnjack/jcode Length of output: 71 🏁 Script executed: cat web/package.json | jq '.scripts'Repository: cnjack/jcode Length of output: 353 Update the CI lint command to run the full linting workflow. The CI runs 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -118,7 +118,7 @@ jobs: | |
| else | ||
| VERSION="${GITHUB_REF#refs/tags/}" | ||
| fi | ||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Build binary | ||
| env: | ||
|
|
@@ -148,8 +148,229 @@ jobs: | |
| name: binaries-${{ matrix.goos }}-${{ matrix.goarch }} | ||
| path: dist/jcode-* | ||
|
|
||
| # Desktop (Tauri) app bundles. Each platform builds on a native runner because | ||
| # Tauri produces OS-native installers (.dmg / .msi / .deb / AppImage). The Go | ||
| # binary is compiled as the Tauri "sidecar" (binaries/jcode-<target-triple>) and | ||
| # embedded into the bundle; at runtime it serves the same web UI on loopback. | ||
| desktop: | ||
| needs: prepare | ||
| runs-on: ${{ matrix.os }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| # macOS Apple Silicon (M-series) | ||
| - os: macos-latest | ||
| triple: aarch64-apple-darwin | ||
| ext: '' | ||
| cgo: 1 | ||
| bundles: dmg | ||
| label: macos-arm64 | ||
| # macOS Intel | ||
| - os: macos-15-intel | ||
| triple: x86_64-apple-darwin | ||
| ext: '' | ||
| cgo: 1 | ||
| bundles: dmg | ||
| label: macos-x64 | ||
| # Windows x64 | ||
| - os: windows-latest | ||
| triple: x86_64-pc-windows-msvc | ||
| ext: '.exe' | ||
| cgo: 0 | ||
| bundles: 'msi,nsis' | ||
| label: windows-x64 | ||
| # Linux x64 | ||
| - os: ubuntu-22.04 | ||
| triple: x86_64-unknown-linux-gnu | ||
| ext: '' | ||
| cgo: 0 | ||
| bundles: 'deb,appimage' | ||
| label: linux-x64 | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v5 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Set up Go | ||
| uses: actions/setup-go@v6 | ||
| with: | ||
| go-version-file: 'go.mod' | ||
|
|
||
| - name: Set up Node.js | ||
| uses: actions/setup-node@v5 | ||
| with: | ||
| node-version: '22' | ||
|
|
||
| - name: Install pnpm | ||
| run: npm install -g pnpm | ||
|
|
||
| - name: Set up Rust | ||
| uses: dtolnay/rust-toolchain@stable | ||
| with: | ||
| targets: ${{ matrix.triple }} | ||
|
|
||
| - name: Cache Rust | ||
| uses: swatinem/rust-cache@v2 | ||
| with: | ||
| workspaces: desktop/src-tauri | ||
|
Comment on lines
+155
to
+218
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. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
python3 - <<'PY'
from pathlib import Path
import re
path = Path(".github/workflows/release.yml")
for lineno, line in enumerate(path.read_text().splitlines(), 1):
match = re.search(r'^\s*uses:\s*([^#\s]+)', line)
if not match:
continue
ref = match.group(1)
if "@" not in ref or not re.search(r'@[0-9a-fA-F]{40}$', ref):
print(f"{path}:{lineno}: {ref}")
PYRepository: cnjack/jcode Length of output: 1181 🏁 Script executed: cat -n .github/workflows/release.yml | head -220Repository: cnjack/jcode Length of output: 7143 🏁 Script executed: cat -n .github/workflows/release.yml | sed -n '235,370p'Repository: cnjack/jcode Length of output: 7002 🏁 Script executed: cat -n .github/workflows/release.yml | sed -n '394,405p'Repository: cnjack/jcode Length of output: 470 Harden the desktop release job before producing artifacts. The desktop job (lines 155-218) and related build steps (lines 235-369, 394-405) run with the default checkout token persisted and use tag-pinned action references instead of immutable SHAs. The job inherits the global All 13 actions in the affected ranges are tag-pinned ( 🔒 Suggested hardening for the desktop job token boundary desktop:
needs: prepare
+ permissions:
+ contents: read
runs-on: ${{ matrix.os }}
@@
- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0
+ persist-credentials: falsePin all workflow action references to full SHAs across lines 155-218, 235-369, and 394-405. Example:
🧰 Tools🪛 zizmor (1.25.2)[warning] 192-195: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) [error] 193-193: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) [error] 198-198: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) [error] 203-203: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) [error] 211-211: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) [error] 216-216: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) [error] 198-198: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): enables caching by default (cache-poisoning) [error] 203-203: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): enables caching by default (cache-poisoning) [error] 216-216: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): enables caching by default (cache-poisoning) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
|
|
||
| - name: Install Linux dependencies | ||
| if: matrix.os == 'ubuntu-22.04' | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y \ | ||
| libwebkit2gtk-4.1-dev \ | ||
| libgtk-3-dev \ | ||
| libayatana-appindicator3-dev \ | ||
| librsvg2-dev \ | ||
| libssl-dev \ | ||
| libxdo-dev \ | ||
| libfuse2 \ | ||
| patchelf \ | ||
| file | ||
|
|
||
| - name: Download prepared artifacts | ||
| uses: actions/download-artifact@v5 | ||
| with: | ||
| name: prepared | ||
| path: internal/ | ||
|
|
||
| - name: Get version | ||
| id: get_version | ||
| shell: bash | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| VERSION="${{ github.event.inputs.version }}" | ||
| else | ||
| VERSION="${GITHUB_REF#refs/tags/}" | ||
| fi | ||
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Sync bundle version | ||
| shell: bash | ||
| run: | | ||
| VER="${{ steps.get_version.outputs.version }}" | ||
| VER="${VER#v}" | ||
| node -e "const fs=require('fs');const f='desktop/src-tauri/tauri.conf.json';const j=JSON.parse(fs.readFileSync(f));j.version='${VER}';fs.writeFileSync(f, JSON.stringify(j,null,2)+'\n')" | ||
| echo "Set desktop bundle version to ${VER}" | ||
|
|
||
| - name: Build sidecar | ||
| shell: bash | ||
| env: | ||
| CGO_ENABLED: ${{ matrix.cgo }} | ||
| run: | | ||
| VERSION="${{ steps.get_version.outputs.version }}" | ||
| COMMIT="$(git rev-parse --short HEAD)" | ||
| mkdir -p desktop/src-tauri/binaries | ||
| go build -trimpath \ | ||
| -ldflags "-s -w -X github.com/cnjack/jcode/internal/command.Version=${VERSION} -X github.com/cnjack/jcode/internal/command.GitCommit=${COMMIT}" \ | ||
| -o "desktop/src-tauri/binaries/jcode-${{ matrix.triple }}${{ matrix.ext }}" \ | ||
|
Comment on lines
+241
to
+270
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. 🧩 Analysis chain🏁 Script executed: # First, let's find and read the workflow file
git ls-files .github/workflows/release.ymlRepository: cnjack/jcode Length of output: 86 🏁 Script executed: # Get the file and check the specific lines
cat -n .github/workflows/release.yml | sed -n '240,275p'Repository: cnjack/jcode Length of output: 1881 🏁 Script executed: # Let's also check the full context of these steps to understand the flow
cat -n .github/workflows/release.yml | sed -n '200,300p'Repository: cnjack/jcode Length of output: 4800 Pass version input through environment variables and validate the format before embedding in scripts. Lines 246, 255, and 265 inject version strings directly from GitHub Actions context expressions into bash and Node scripts, creating injection vulnerabilities. A crafted version like
See suggested implementation in the details section below: 🛡️ Safer version handling - name: Get version
id: get_version
shell: bash
+ env:
+ WORKFLOW_VERSION: ${{ github.event.inputs.version }}
run: |
- if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
- VERSION="${{ github.event.inputs.version }}"
+ if [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ]; then
+ VERSION="$WORKFLOW_VERSION"
else
VERSION="${GITHUB_REF#refs/tags/}"
fi
- echo "version=$VERSION" >> "$GITHUB_OUTPUT"
+ if [[ ! "$VERSION" =~ ^v?[0-9]+[.][0-9]+[.][0-9]+(-[0-9A-Za-z.-]+)?([+][0-9A-Za-z.-]+)?$ ]]; then
+ echo "::error::invalid release version: $VERSION"
+ exit 1
+ fi
+ printf 'version=%s\n' "$VERSION" >> "$GITHUB_OUTPUT"
@@
- name: Sync bundle version
shell: bash
+ env:
+ RELEASE_VERSION: ${{ steps.get_version.outputs.version }}
run: |
- VER="${{ steps.get_version.outputs.version }}"
- VER="${VER#v}"
- node -e "const fs=require('fs');const f='desktop/src-tauri/tauri.conf.json';const j=JSON.parse(fs.readFileSync(f));j.version='${VER}';fs.writeFileSync(f, JSON.stringify(j,null,2)+'\n')"
+ VER="${RELEASE_VERSION#v}"
+ export BUNDLE_VERSION="$VER"
+ node <<'NODE'
+ const fs = require('fs')
+ const f = 'desktop/src-tauri/tauri.conf.json'
+ const j = JSON.parse(fs.readFileSync(f, 'utf8'))
+ j.version = process.env.BUNDLE_VERSION
+ fs.writeFileSync(f, JSON.stringify(j, null, 2) + '\n')
+ NODE
echo "Set desktop bundle version to ${VER}"
@@
env:
CGO_ENABLED: ${{ matrix.cgo }}
+ RELEASE_VERSION: ${{ steps.get_version.outputs.version }}
run: |
- VERSION="${{ steps.get_version.outputs.version }}"
+ VERSION="$RELEASE_VERSION"
COMMIT="$(git rev-parse --short HEAD)"🧰 Tools🪛 zizmor (1.25.2)[error] 246-246: code injection via template expansion (template-injection): may expand into attacker-controllable code (template-injection) [info] 255-255: code injection via template expansion (template-injection): may expand into attacker-controllable code (template-injection) [info] 265-265: code injection via template expansion (template-injection): may expand into attacker-controllable code (template-injection) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
| ./cmd/jcode/ | ||
|
|
||
| # macOS signing + notarization. Everything here is optional: with no secrets | ||
| # the build still succeeds and produces an UNSIGNED bundle (Gatekeeper warns | ||
| # on first launch). When the secrets are present, the Tauri CLI imports the | ||
| # cert into a temp keychain, signs with Developer ID, then notarizes. | ||
| # | ||
| # We resolve the credentials into $GITHUB_ENV here (rather than as a static | ||
| # env block on the build step) for two reasons: the notarization .p8 is a | ||
| # FILE that must be written to disk from a base64 secret, and the two notary | ||
| # auth methods are mutually exclusive — exporting only the configured one | ||
| # avoids an empty APPLE_ID accidentally selecting the Apple-ID path. | ||
| - name: Set up macOS signing & notarization | ||
| if: runner.os == 'macOS' | ||
| shell: bash | ||
| env: | ||
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | ||
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | ||
| APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} | ||
| # Notarization — App Store Connect API key (.p8), preferred for CI. | ||
| APPLE_API_KEY_P8_BASE64: ${{ secrets.APPLE_API_KEY_P8_BASE64 }} | ||
| APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} | ||
| APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | ||
| # Notarization — Apple ID (alternative; use one method, not both). | ||
| APPLE_ID: ${{ secrets.APPLE_ID }} | ||
| APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} | ||
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | ||
| run: | | ||
| # Code-signing certificate (Tauri imports it from these env vars). | ||
| if [ -n "$APPLE_CERTIFICATE" ]; then | ||
| { | ||
| echo "APPLE_CERTIFICATE=$APPLE_CERTIFICATE" | ||
| echo "APPLE_CERTIFICATE_PASSWORD=$APPLE_CERTIFICATE_PASSWORD" | ||
| } >> "$GITHUB_ENV" | ||
| [ -n "$APPLE_SIGNING_IDENTITY" ] && echo "APPLE_SIGNING_IDENTITY=$APPLE_SIGNING_IDENTITY" >> "$GITHUB_ENV" | ||
| echo "code-signing: enabled" | ||
| else | ||
| echo "code-signing: DISABLED (APPLE_CERTIFICATE unset) — bundle will be unsigned" | ||
| fi | ||
|
|
||
| # Notarization auth — pick exactly one method. | ||
| if [ -n "$APPLE_API_KEY_P8_BASE64" ]; then | ||
| # APPLE_API_KEY is the Key ID STRING; the .p8 key material is a file | ||
| # referenced by APPLE_API_KEY_PATH. Decode the base64 secret to disk. | ||
| KEY_PATH="$RUNNER_TEMP/AuthKey_${APPLE_API_KEY_ID}.p8" | ||
| echo -n "$APPLE_API_KEY_P8_BASE64" | base64 --decode > "$KEY_PATH" | ||
| { | ||
| echo "APPLE_API_ISSUER=$APPLE_API_ISSUER" | ||
| echo "APPLE_API_KEY=$APPLE_API_KEY_ID" | ||
| echo "APPLE_API_KEY_PATH=$KEY_PATH" | ||
| } >> "$GITHUB_ENV" | ||
| echo "notarization: App Store Connect API key" | ||
| elif [ -n "$APPLE_ID" ]; then | ||
| { | ||
| echo "APPLE_ID=$APPLE_ID" | ||
| echo "APPLE_PASSWORD=$APPLE_PASSWORD" | ||
| echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" | ||
| } >> "$GITHUB_ENV" | ||
| echo "notarization: Apple ID" | ||
| else | ||
| echo "notarization: DISABLED (no API key or Apple ID secrets)" | ||
| fi | ||
|
|
||
| - name: Build desktop bundle | ||
| shell: bash | ||
| working-directory: desktop | ||
| env: | ||
| # Lets linuxdeploy build the AppImage on runners without FUSE mounted. | ||
| # The macOS signing/notarization vars arrive via $GITHUB_ENV (above). | ||
| APPIMAGE_EXTRACT_AND_RUN: 1 | ||
| run: | | ||
| pnpm install --frozen-lockfile | ||
| pnpm tauri build --bundles ${{ matrix.bundles }} | ||
|
|
||
| - name: Collect bundles | ||
| shell: bash | ||
| run: | | ||
| mkdir -p dist-desktop | ||
| B="desktop/src-tauri/target/release/bundle" | ||
| shopt -s nullglob 2>/dev/null || true | ||
| for f in "$B"/dmg/*.dmg "$B"/msi/*.msi "$B"/nsis/*-setup.exe "$B"/deb/*.deb "$B"/appimage/*.AppImage; do | ||
| [ -f "$f" ] && cp "$f" dist-desktop/ | ||
| done | ||
| cd dist-desktop | ||
| for f in *; do | ||
| [ -f "$f" ] || continue | ||
| if command -v sha256sum >/dev/null 2>&1; then | ||
| sha256sum "$f" > "$f.sha256" | ||
| else | ||
| shasum -a 256 "$f" > "$f.sha256" | ||
| fi | ||
| done | ||
| ls -la | ||
|
|
||
| - name: Upload desktop bundles | ||
| uses: actions/upload-artifact@v5 | ||
| with: | ||
| name: desktop-${{ matrix.label }} | ||
| path: dist-desktop/* | ||
| if-no-files-found: error | ||
|
|
||
| release: | ||
| needs: build | ||
| needs: [build, desktop] | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
|
|
@@ -168,18 +389,26 @@ jobs: | |
| else | ||
| VERSION="${GITHUB_REF#refs/tags/}" | ||
| fi | ||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Download all artifacts | ||
| - name: Download CLI binaries | ||
| uses: actions/download-artifact@v5 | ||
| with: | ||
| path: dist | ||
| pattern: binaries-* | ||
| merge-multiple: true | ||
|
|
||
| - name: Download desktop bundles | ||
| uses: actions/download-artifact@v5 | ||
| with: | ||
| path: dist-desktop | ||
| pattern: desktop-* | ||
| merge-multiple: true | ||
|
|
||
| - name: List artifacts | ||
| run: | | ||
| ls -la dist/ | ||
| echo "── CLI binaries ──"; ls -la dist/ | ||
| echo "── Desktop bundles ──"; ls -la dist-desktop/ | ||
|
|
||
| - name: Create Release | ||
| uses: softprops/action-gh-release@v2 | ||
|
|
@@ -190,6 +419,7 @@ jobs: | |
| prerelease: ${{ contains(steps.get_version.outputs.version, 'alpha') || contains(steps.get_version.outputs.version, 'beta') || contains(steps.get_version.outputs.version, 'rc') }} | ||
| files: | | ||
| dist/jcode-* | ||
| dist-desktop/* | ||
| generate_release_notes: true | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
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.
Disable credential persistence on checkout actions.
The
actions/checkout@v5actions default topersist-credentials: true, which leaves the GitHub token in~/.netrcfor the duration of the job. This is unnecessary for read-only CI and increases the surface for token exfiltration. Setpersist-credentials: falseexplicitly.🔒 Proposed fix: disable credential persistence
- uses: actions/checkout@v5 with: fetch-depth: 0 + persist-credentials: falseApply the same change to line 62.
Also applies to: 62-62
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 22-25: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 22-22: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 Prompt for AI Agents
Source: Linters/SAST tools
Pin action versions to commit hashes for supply-chain security.
All action references use major version tags (
@v5,@v6,@v7), which point to a moving target. Consider pinning to a commit hash (e.g.,actions/checkout@a1b2c3d4e5f6...) to protect against unexpected upstream changes and prevent exploitation if an action's tag is mutated. This is especially important for security-sensitive workflows.🔒 Proposed fix: pin action versions
Example pins (check the latest release commit for each action):
Find the actual commit SHAs via the GitHub action's release page or
gh api repos/{owner}/{repo}/releases/{tag}.Also applies to: 27-27, 47-47, 62-62, 64-64
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 22-25: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 22-22: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 Prompt for AI Agents
Source: Linters/SAST tools