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
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ jobs:
command: cargo test
cache: true
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: jdx/mise-action@7e36c90d9ab29c415a2384db3006f3ec8a8cc654 # v4.2.4
with:
install_args: rust
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
Comment on lines +38 to +42

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 | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- workflow files ---'
sed -n '1,130p' .github/workflows/ci.yml
printf '%s\n' '--- release workflow ---'
sed -n '1,125p' .github/workflows/release.yml
printf '%s\n' '--- checkout and git-write references ---'
rg -n -C 3 'actions/checkout|persist-credentials|git push|git commit|git tag|gh release|release' .github/workflows

Repository: sou1118/typdiff

Length of output: 10149


🏁 Script executed:

#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re

files = [Path(".github/workflows/ci.yml"), Path(".github/workflows/release.yml")]
text = {p: p.read_text() for p in files}

for path, body in text.items():
    lines = body.splitlines()
    print(f"--- {path} ---")
    workflow_permissions = []
    for i, line in enumerate(lines):
        if re.match(r"^permissions:", line):
            workflow_permissions = lines[i:i+4]
            break
    print("workflow_permissions:", " | ".join(x.strip() for x in workflow_permissions))

    for i, line in enumerate(lines):
        if re.match(r"^\s+- uses: actions/checkout@", line):
            indent = len(line) - len(line.lstrip())
            job = "unknown"
            for j in range(i - 1, -1, -1):
                m = re.match(r"^  ([A-Za-z0-9_-]+):\s*$", lines[j])
                if m and m.group(1) not in {"steps", "strategy", "matrix", "include"}:
                    job = m.group(1)
                    break
            inputs = []
            for candidate in lines[i+1:]:
                candidate_indent = len(candidate) - len(candidate.lstrip())
                if candidate.strip() and candidate_indent <= indent:
                    break
                if "persist-credentials:" in candidate:
                    inputs.append(candidate.strip())
            print(f"checkout line {i+1}, job={job}, persist_inputs={inputs or ['(default)']}")
            end = len(lines)
            for j in range(i+1, len(lines)):
                if re.match(r"^  [A-Za-z0-9_-]+:\s*$", lines[j]):
                    end = j
                    break
            job_block = lines[i:end]
            writes = [x.strip() for x in job_block if re.search(r"\bgit\s+(push|commit|tag)\b", x)]
            print("  explicit_git_write_commands:", writes or ["(none)"])
PY

Repository: sou1118/typdiff

Length of output: 764


Security Misconfiguration (CWE-522): Insufficiently Protected Credentials

Reachability: Internal · Exploitability: Difficult

Disable credential persistence on all four checkout steps. Add persist-credentials: false at .github/workflows/ci.yml:38, .github/workflows/ci.yml:51, .github/workflows/release.yml:40, and .github/workflows/release.yml:100. Also set permissions: contents: read for the release.build job.

🧰 Tools
🪛 zizmor (1.29.0)

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

(artipacked)

📍 Affects 2 files
  • .github/workflows/ci.yml#L38-L42 (this comment)
  • .github/workflows/ci.yml#L51-L53
  • .github/workflows/release.yml#L40-L40
  • .github/workflows/release.yml#L100-L100
🤖 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.yml around lines 38 - 42, Disable credential
persistence on all checkout steps: add persist-credentials: false at
.github/workflows/ci.yml lines 38-42 and 51-53, and
.github/workflows/release.yml lines 40 and 100. Also set permissions to
contents: read for the release.build job.

Source: Linters/SAST tools

if: ${{ matrix.cache }}
- run: ${{ matrix.command }}

Expand All @@ -48,9 +48,9 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: jdx/mise-action@7e36c90d9ab29c415a2384db3006f3ec8a8cc654 # v4.2.4
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- name: Build typdiff
run: cargo build
- name: Diff and compile (basic fixtures)
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
runner: windows-latest
cross: false
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: jdx/mise-action@7e36c90d9ab29c415a2384db3006f3ec8a8cc654 # v4.2.4
with:
install_args: rust
Expand All @@ -64,7 +64,7 @@ jobs:
shell: pwsh
run: |
Compress-Archive -Path target/${{ matrix.target }}/release/typdiff.exe -DestinationPath typdiff-${{ matrix.target }}.zip
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: typdiff-${{ matrix.target }}
path: typdiff-${{ matrix.target }}.*
Expand All @@ -76,12 +76,12 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/download-artifact@v7
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: artifacts
merge-multiple: true
- name: Create GitHub Release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
with:
generate_release_notes: true
files: artifacts/*
Expand All @@ -97,13 +97,13 @@ jobs:
id-token: write
contents: read
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: jdx/mise-action@7e36c90d9ab29c415a2384db3006f3ec8a8cc654 # v4.2.4
with:
install_args: rust
- name: Authenticate with crates.io
id: auth
uses: rust-lang/crates-io-auth-action@b7e9a28eded4986ec6b1fa40eeee8f8f165559ec # v1.0.3
uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5
Comment on lines +100 to +106

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

🧩 Analysis chain

🏁 Script executed:

# Read the full release.yml workflow to understand job permissions and context
cat -n .github/workflows/release.yml

Repository: sou1118/typdiff

Length of output: 4309


🏁 Script executed:

# Check if there's documentation or defaults for jdx/mise-action caching
# First, let's see if there's an action.yml in the repository for this
fd -e yml -e yaml | head -20

Repository: sou1118/typdiff

Length of output: 153


🌐 Web query:

jdx/mise-action caching default behavior GitHub Actions

💡 Result:

The jdx/mise-action GitHub Action enables caching by default, which is designed to improve workflow performance by storing and retrieving mise tool installations using the GitHub Actions Cache service [1][2][3]. Key aspects of the default caching behavior include: * Caching is enabled by default (cache: true) [1][4]. * The action generates a default cache key using a template that incorporates various environmental and configuration factors, such as the mise version, platform, and a hash of configuration files (e.g., .tool-versions or mise.toml) [1][5][2]. * When a cache hit occurs, the action restores the cached directory, which typically contains the installed tools, allowing the workflow to skip redundant installation steps [3]. * If you need to disable caching, you can set the cache input to false [1][5]. * You can further customize or override the default caching behavior using the cache_key or cache_key_prefix inputs [4][2][6]. Using the cache_key input allows you to use template variables (e.g., {{file_hash}}, {{version}}, {{platform}}) to create fine-grained cache keys [2][6]. Because the default cache key includes a hash of your configuration files and the mise version, the cache is automatically invalidated when your tools or mise version change [5][7][2]. However, if you experience issues with stale caches or need to force updates, you can modify the cache_key_prefix or provide a custom cache_key [2][6]. Users experiencing issues where the action fails to pick up newer tool versions or mise updates despite configuration changes sometimes opt to disable caching or manually append unique values to the cache key [8][7].

Citations:


Security Misconfiguration (CWE-829): Inclusion of Functionality from Untrusted Control Sphere

Reachability: Internal

Disable caching in jdx/mise-action for the publish job.

The publish job requests id-token: write and exchanges it for a crates.io token via rust-lang/crates-io-auth-action. jdx/mise-action enables caching by default. The cache key includes a hash of configuration files, making it deterministic and predictable. A contributor with push access could poison the cache by committing to the release branch before the tag is pushed. The poisoned cache would be restored during the publish job and executed before or during cargo publish with the OIDC-derived credential.

Disable caching for this job by adding cache: false to the action inputs. This eliminates the cache-poisoning attack surface for this security-sensitive operation with minimal performance cost.

🧰 Tools
🪛 zizmor (1.29.0)

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

(artipacked)


[error] 101-101: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): enables caching by default

(cache-poisoning)

🤖 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/release.yml around lines 100 - 106, The jdx/mise-action
step in the publish job has caching enabled by default, which creates a security
vulnerability where a poisoned cache could be executed with OIDC-derived
credentials during cargo publish. Add cache: false to the with section of the
jdx/mise-action step alongside the existing install_args input to disable
caching and eliminate this attack surface.

Source: Linters/SAST tools

- name: Publish
run: cargo publish
env:
Expand Down