Skip to content

refactor: reorganize repository and update Restate SDK - #47

Merged
sagikazarmark merged 1 commit into
mainfrom
repo-reorg
Jul 26, 2026
Merged

refactor: reorganize repository and update Restate SDK#47
sagikazarmark merged 1 commit into
mainfrom
repo-reorg

Conversation

@sagikazarmark

@sagikazarmark sagikazarmark commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added standalone FFmpeg endpoint documentation with quick-start instructions, container usage, configuration options, and OpenDAL settings.
    • Expanded configurable service and handler options, including metadata, timeouts, retention, ingress, retries, and lazy-state behavior.
    • Improved service discovery and handler registration for FFmpeg and FFprobe operations.
  • Bug Fixes

    • Containers now run as a non-root user.
  • Documentation

    • Added usage guides for the reusable FFmpeg service and endpoint.
  • Chores

    • Updated automated checks and build workflows for more reliable validation and faster container rebuilds.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The workspace updates Restate FFmpeg service registration, endpoint configuration, Docker packaging, and repository automation. Dagger modules now build and validate the endpoint deployment, while previous devenv-based CI workflows and setup actions are removed.

Changes

Service and CI migration

Layer / File(s) Summary
Service contract and workspace packages
Cargo.toml, crates/restate-ffmpeg/Cargo.toml, crates/restate-ffmpeg/src/*, crates/restate-ffmpeg/README.md
The FFmpeg service uses Restate service and handler macros, exposes the service module at the crate root, updates SDK features, and adds discovery metadata tests.
Endpoint configuration and binding
crates/restate-ffmpeg-endpoint/Cargo.toml, crates/restate-ffmpeg-endpoint/src/*, crates/restate-ffmpeg-endpoint/README.md
Service and handler options are deserialized and converted into SDK options, then applied during direct endpoint binding.
Container dependency caching and runtime
Dockerfile, .dockerignore, .github/workflows/artifacts.yaml
The image build uses cargo-chef stages, builds the endpoint package, updates runtime images, publishes through newer actions, and runs as a non-root user.
Dagger endpoint validation and CI
.dagger/modules/tests/*, dagger.toml, .github/workflows/dagger.yaml, devenv.*, .github/dependabot.yaml
Dagger builds and deploys the endpoint, queries Restate deployment metadata, validates the FFmpeg service, and replaces the previous CI workflow with locked Dagger checks.
Repository automation and development configuration
.cargo/audit.toml, .editorconfig, .gitignore, .github/workflows/analysis-scorecard.yaml, README.md
Advisory suppressions, formatting rules, ignore patterns, action pins, and repository introductory text are updated; prior devenv and Rust setup actions and CI workflows are removed.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Dagger
  participant Rust
  participant Container
  participant Restate
  Dagger->>Rust: build restate-ffmpeg endpoint
  Rust->>Container: package binary and expose port 9080
  Dagger->>Restate: deploy container
  Dagger->>Restate: query sys_deployment
  Restate-->>Dagger: return endpoint and FFmpeg service metadata
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes: repository reorganization and a Restate SDK update.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch repo-reorg

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
crates/restate-ffmpeg-endpoint/src/restate_config.rs (1)

8-89: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reduce duplication between ServiceOptionsConfig/HandlerOptionsConfig and their From impls.

The two config structs and their From impls are ~90% identical boilerplate (same if let Some(x) = config.x { opts = opts.x(x); } pattern repeated per field). This already shows drift (e.g. workflow_retention only exists on the handler side, field order differs). A declarative macro generating the common Option<T> fields + conversion arms would cut ~120 lines of near-duplicate code and reduce the risk of missed updates when new SDK options are added.

♻️ Sketch of a macro-based reduction
+macro_rules! apply_common_options {
+    ($opts:expr, $config:expr, [$($field:ident),* $(,)?]) => {
+        $(
+            if let Some(value) = $config.$field {
+                $opts = $opts.$field(value);
+            }
+        )*
+    };
+}

This could be applied for the shared timeout/retention/retry fields in both From impls, leaving only the truly divergent fields (handlers for service, workflow_retention for handler) handled explicitly.

Also applies to: 99-223

🤖 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 `@crates/restate-ffmpeg-endpoint/src/restate_config.rs` around lines 8 - 89,
Reduce duplication between ServiceOptionsConfig and HandlerOptionsConfig and
their From implementations by introducing a declarative macro for shared
optional SDK fields and their corresponding builder conversion arms. Apply it to
the common timeout, retention, and retry-policy options while keeping
ServiceOptionsConfig.handlers and HandlerOptionsConfig.workflow_retention
explicitly defined, and preserve each existing field’s serde attributes and
conversion behavior.
🤖 Prompt for all review comments with 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.

Inline comments:
In @.cargo/audit.toml:
- Around line 1-4: Update the [advisories] configuration around the global
ignore list to either upgrade or patch the transitive rsa and quick-xml
dependencies, or add explicit documentation demonstrating that their vulnerable
paths cannot receive untrusted input before retaining the ignores. Keep each
advisory suppression scoped to its verified justification rather than leaving
undocumented global ignores.

In @.github/workflows/dagger.yaml:
- Around line 8-9: Update the Dagger workflow generator’s actions/checkout
configuration to set persist-credentials to false, then regenerate
.github/workflows/dagger.yaml so the generated checkout step includes that
setting.
- Around line 8-15: Pin the generated action references in
.github/workflows/dagger.yaml at lines 8-15 to immutable full commit SHAs,
retaining version comments where useful for maintenance. Update
.github/dependabot.yaml at lines 26-31 to remove the github-actions exclusion,
or add an equivalent generator-level update policy, so all pinned workflow
actions remain covered by update automation.

---

Nitpick comments:
In `@crates/restate-ffmpeg-endpoint/src/restate_config.rs`:
- Around line 8-89: Reduce duplication between ServiceOptionsConfig and
HandlerOptionsConfig and their From implementations by introducing a declarative
macro for shared optional SDK fields and their corresponding builder conversion
arms. Apply it to the common timeout, retention, and retry-policy options while
keeping ServiceOptionsConfig.handlers and
HandlerOptionsConfig.workflow_retention explicitly defined, and preserve each
existing field’s serde attributes and conversion behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9ef4a1ec-850e-4e48-b2cb-c0c8649ef7b2

📥 Commits

Reviewing files that changed from the base of the PR and between e909906 and 703ed0e.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • dagger.lock is excluded by !**/*.lock
  • devenv.lock is excluded by !**/*.lock
📒 Files selected for processing (30)
  • .cargo/audit.toml
  • .dagger/modules/tests/dagger-module.toml
  • .dagger/modules/tests/main.dang
  • .dockerignore
  • .editorconfig
  • .envrc
  • .github/actions/devenv/action.yaml
  • .github/actions/rust/action.yaml
  • .github/dependabot.yaml
  • .github/workflows/analysis-scorecard.yaml
  • .github/workflows/artifacts.yaml
  • .github/workflows/ci-nix.yaml
  • .github/workflows/ci.yaml
  • .github/workflows/dagger.yaml
  • .gitignore
  • Cargo.toml
  • Dockerfile
  • README.md
  • crates/restate-ffmpeg-endpoint/Cargo.toml
  • crates/restate-ffmpeg-endpoint/README.md
  • crates/restate-ffmpeg-endpoint/src/config.rs
  • crates/restate-ffmpeg-endpoint/src/main.rs
  • crates/restate-ffmpeg-endpoint/src/restate_config.rs
  • crates/restate-ffmpeg/Cargo.toml
  • crates/restate-ffmpeg/README.md
  • crates/restate-ffmpeg/src/lib.rs
  • crates/restate-ffmpeg/src/service.rs
  • dagger.toml
  • devenv.nix
  • devenv.yaml
💤 Files with no reviewable changes (5)
  • .github/workflows/ci-nix.yaml
  • .github/actions/rust/action.yaml
  • .envrc
  • .github/workflows/ci.yaml
  • .github/actions/devenv/action.yaml

Comment thread .cargo/audit.toml
Comment on lines +1 to +4
[advisories]
# restate-sdk transitively uses rsa 0.9.10, which has no fixed release.
# OpenDAL 0.57 pins quick-xml 0.39; no patched OpenDAL release is available yet.
ignore = ["RUSTSEC-2023-0071", "RUSTSEC-2026-0194", "RUSTSEC-2026-0195"]

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== audit config =="
cat -n .cargo/audit.toml

echo
echo "== RustSec advisories summary =="
rg -n 'RUSTSEC-2023-0071|RUSTSEC-2026-0194|RUSTSEC-2026-0195' . -S || true

echo
echo "== dependency files =="
git ls-files | rg '(^|/)(Cargo\.toml|Cargo\.lock|Cargo\.toml\.lock)$'

echo
echo "== quick-xml dependency occurrences =="
rg -n 'quick-xml|rsa|OpenDAL|restate-sdk' Cargo.toml Cargo.lock -S || true

Repository: sagikazarmark/restate-ffmpeg

Length of output: 1379


🌐 Web query:

RUSTSEC-2023-0071 rsa timing attack patched fix no patched release

💡 Result:

As of July 26, 2026, the RUSTSEC-2023-0071 vulnerability (also tracked as CVE-2023-49092) concerning a timing side-channel attack in the Rust rsa crate has not been formally marked as patched in the primary RustSec advisory database [1][2][3]. While official advisory records continue to list "no patched versions" [1][2][4], active development and mitigation efforts are underway within the RustCrypto/RSA repository [5][6]. Recent contributions, such as Pull Request #702, have focused on implementing defense-in-depth measures, including restoring default RSA blinding for decryption paths and addressing the behavioral PKCS#1 v1.5 decryption oracle [6][7]. Users requiring immediate mitigation are advised to consider the following: 1. Workarounds: The primary recommendation remains avoiding the use of the rsa crate in environments where attackers can observe network-level timing information [1][4]. 2. Alternative Implementations: A security-focused fork named sad_rsa exists, which explicitly claims to implement implicit rejection for PKCS#1 v1.5 decryption specifically to mitigate the Marvin Attack (RUSTSEC-2023-0071) [8]. Developers should monitor the official GitHub repository for the rsa crate and the RustSec advisory database for status updates regarding a formal release that fully addresses the vulnerability [1][5].

Citations:


🌐 Web query:

RUSTSEC-2026-0194 quick-xml denial-of-service patched version 0.41

💡 Result:

RUSTSEC-2026-0194 is a denial-of-service (DoS) vulnerability in the quick-xml crate related to quadratic runtime performance when parsing XML attributes [1][2]. Vulnerability Summary: The BytesStart::attributes() method (and internal consumers like NsReader) performs a linear scan of previously seen attribute names to detect duplicates [1][3]. Because this check was performed using an O(N²) approach where N is the number of attributes in a single start tag, an attacker could provide a crafted XML input with a large number of attributes to exhaust CPU resources, effectively stalling the parsing thread for an extended period [1][2][4]. Resolution: This vulnerability is resolved in quick-xml version 0.41.0 and later [1][2][3]. The patched version updates the duplicate-checking logic to use an O(1) hash pre-filter for tags with a large number of attributes, reducing the overall complexity to O(N) [1][2]. Mitigation: If upgrading to version 0.41.0 is not immediately feasible and duplicate-name detection is not required for your use case, the vulnerability can be mitigated by disabling the check using .attributes().with_checks(false) [1][2]. Note that this opt-out mechanism was not available for NsReader consumers prior to version 0.41.0 [1][4].

Citations:


🌐 Web query:

RUSTSEC-2026-0195 quick-xml denial-of-service patched version 0.41

💡 Result:

RUSTSEC-2026-0195 is a security advisory for the quick-xml Rust crate concerning an unbounded namespace-declaration allocation vulnerability [1][2]. The issue occurs within NsReader, which processes namespace declarations before yielding events to the consumer [1][3]. By providing a crafted XML start tag with a large number of namespace declarations, an attacker could force the parser to perform excessive heap allocations, leading to a memory-exhaustion denial-of-service (DoS) condition [1][2][4]. The issue was addressed in version 0.41.0 of quick-xml [3][5]. Key details of the fix include: - The parser now enforces a limit of 256 namespace bindings per element by default (defined as DEFAULT_MAX_DECLARATIONS_PER_ELEMENT) [1][5]. - When this limit is exceeded, NamespaceResolver::push returns a new NamespaceError::TooManyDeclarations error instead of allocating memory [1][5]. - The limit is configurable via NamespaceResolver::set_max_declarations_per_element (or can be disabled by setting it to usize::MAX) [1][5]. - NsReader::resolver_mut was added to allow access to the resolver for configuring these limits [1][5]. It is recommended to upgrade to quick-xml version 0.41.0 or later to mitigate this vulnerability [1][3][6]. There is no effective workaround for versions prior to 0.41.0, as the allocation occurs internally before the consumer can inspect or reject the event [1][2][3]. This advisory is often cited alongside RUSTSEC-2026-0194, which covers a related CPU-exhaustion DoS vulnerability involving duplicate attribute checks [7][8].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import tomllib
from pathlib import Path

deps = toml.load(Path("Cargo.lock").read_bytes())["package"]
find = {n.strip(): [] for n in ("rsa", "quick-xml", "restate-sdk", "OpenDAL", "opendal")}
for p in deps:
    name = p.get("name")
    version = p.get("version")
    if name in find:
        print(f"package {name} {version}:")
        for dep in p.get("dependencies", []):
            if isinstance(dep, str):
                if dep in find:
                    find[dep].append(name)
            elif dep.get("name") in find:
                find[dep.get("name")].append(name)
        print(" depends_on:")
        print("  " + "\n  ".join(p.get("dependencies") or []))
print("\ndirect reverse paths to ignored advisories:")
for name in ("rsa", "quick-xml"):
    for rev in find[name]:
        print(f"{name} <- {rev}")
PY

echo
echo "== Cargo.toml relevant dependency lines =="
awk '
/^\[[[:space:]]*dependencies[[:space:]]*\]/, /^\[[[:space:]]/ {
  if (/restate-sdk|OpenDAL|opendal|quick-xml|rsa/) print NR": "$0
}
' Cargo.toml

Repository: sagikazarmark/restate-ffmpeg

Length of output: 277


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import tomllib
from pathlib import Path

deps = tomllib.loads(Path("Cargo.lock").read_text())["package"]
find = {n.strip(): [] for n in ("rsa", "quick-xml", "restate-sdk", "OpenDAL", "opendal")}
for p in deps:
    name = p.get("name")
    version = p.get("version")
    if name in find:
        print(f"package {name} {version}:")
        for dep in p.get("dependencies", []):
            if isinstance(dep, str):
                if dep in find:
                    find[dep].append(name)
            elif isinstance(dep, dict) and dep.get("name") in find:
                find[dep["name"]].append(name)
        print(" depends_on:")
        print("  " + "\n  ".join(str(d) for d in (p.get("dependencies") or [])))
print("\ndirect reverse paths to ignored advisories:")
for name in ("rsa", "quick-xml"):
    for rev in find[name]:
        print(f"{name} <- {rev}")
PY

echo
echo "== Cargo.toml relevant dependency lines =="
awk '
/^\[[[:space:]]*dependencies[[:space:]]*\]/, /^\[[[:space:]]/ {
  if (/restate-sdk|OpenDAL|opendal|quick-xml|rsa/) print NR": "$0
}
' Cargo.toml

Repository: sagikazarmark/restate-ffmpeg

Length of output: 1225


Add reachability documentation or upstream fixes before keeping these global ignores.

These advisories cover transitive quick-xml XML parsing paths and a transitive rsa crypto timing side-channel. Document why the vulnerable paths are not reachable from untrusted input, or upgrade/patch before relying on global audit suppression.

🤖 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 @.cargo/audit.toml around lines 1 - 4, Update the [advisories] configuration
around the global ignore list to either upgrade or patch the transitive rsa and
quick-xml dependencies, or add explicit documentation demonstrating that their
vulnerable paths cannot receive untrusted input before retaining the ignores.
Keep each advisory suppression scoped to its verified justification rather than
leaving undocumented global ignores.

Source: MCP tools

Comment on lines +8 to +9
- name: Checkout repository
uses: actions/checkout@v7.0.1

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:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpt =="
sed -n '1,120p' .github/workflows/dagger.yaml || true

echo "== relevant action checkout inputs/usages in workflow =="
rg -n "actions/checkout|persist-credentials|permissions:|pull-request|contents: read|permissions:" .github/workflows/dagger.yaml

echo "== workflow head =="
sed -n '1,80p' .github/workflows/dagger.yaml

echo "== git tracked workflow files =="
git ls-files '.github/workflows/*'

echo "== references to dagger.yaml generation or template =="
rg -n "dagger\.ya?ml|dagger-ci|generate|dependabot|exclude|pull_request" .github/dagger*.yml .github/workflows/dagger.yaml .github 2>/dev/null || true

Repository: sagikazarmark/restate-ffmpeg

Length of output: 2017


🌐 Web query:

actions/checkout persist-credentials default true GitHub Actions checkout

💡 Result:

In the actions/checkout GitHub Action, the persist-credentials input parameter controls whether the authentication token or SSH key used for the checkout is configured in the local git environment [1][2]. When persist-credentials is set to true (which is the default behavior), the action configures the authentication credentials into the git environment [1][3]. This allows subsequent steps in the same workflow job to execute authenticated git commands (such as git push or git fetch) without needing to manually re-authenticate [1][4]. During post-job cleanup, the action automatically removes these credentials [1][2]. To opt out of this behavior, you can set the parameter to false [1][2]: - uses: actions/checkout@v4 with: persist-credentials: false While there has been community discussion and proposed changes to switch the default to false to improve security by default [5][6], as of July 2026, the default value remains true [1][3]. Recent versions of actions/checkout have improved security by storing these credentials in a separate file under $RUNNER_TEMP rather than directly in.git/config, though the core functionality of persisting them for the duration of the job remains [4][7].

Citations:


Disable checkout credential persistence.

This PR-triggered workflow checks out the repository before running Dagger, and actions/checkout persists the GitHub token by default. Set persist-credentials: false to limit token visibility to later steps and packaged workspace contents. Since this workflow is generated by Dagger, apply the change in the generator and regenerate .github/workflows/dagger.yaml.

🧰 Tools
🪛 zizmor (1.26.1)

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

(artipacked)

🤖 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/dagger.yaml around lines 8 - 9, Update the Dagger workflow
generator’s actions/checkout configuration to set persist-credentials to false,
then regenerate .github/workflows/dagger.yaml so the generated checkout step
includes that setting.

Source: Linters/SAST tools

Comment on lines +8 to +15
- name: Checkout repository
uses: actions/checkout@v7.0.1
- name: Check
uses: dagger/dagger-for-github@v8.4.1
with:
args: --lock pinned
verb: check
version: v1.0.0-beta.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.

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)(dagger\.yaml|dependabot\.yaml|package|pyproject|Task|justfile\.ya?ml|dagger\.)$|^\.' || true

echo "== target files =="
for f in .github/workflows/dagger.yaml .github/dependabot.yaml; do
  if [ -f "$f" ]; then
    echo "--- $f ($(wc -l < "$f") lines) ---"
    sed -n '1,120p' "$f"
  else
    echo "missing $f"
  fi
done

echo "== references to dependency update/action pins =="
rg -n "github-actions|pin|pinned|workflow\|actions|dependabot|exclude-paths|dagger-for-github|actions/checkout" .github . 2>/dev/null | head -200

Repository: sagikazarmark/restate-ffmpeg

Length of output: 3656


🌐 Web query:

GitHub Dependabot updates GitHub Actions action references workflow syntax excludes paths docs

💡 Result:

To exclude specific paths from GitHub Dependabot version updates, you can use the exclude-paths configuration option within your dependabot.yml file [1][2]. This option allows you to skip dependency manifests in specific subdirectories or files that you do not want Dependabot to monitor, such as test fixtures, examples, or vendored code [1][2]. Key details about using exclude-paths: Configuration: Add the exclude-paths key to the specific package-ecosystem block in your .github/dependabot.yml file [1][3]. Syntax: It accepts a list of glob patterns, which are evaluated relative to the directory specified for that ecosystem [1][3]. Supported Patterns: You can use standard glob patterns, including `` for recursive matching and * for single-segment wildcards [1][3]. Behavior: When defined, Dependabot ignores all files and directories matching these patterns during its update scans for that specific configuration block [1][2]. This prevents Dependabot from parsing manifests or opening pull requests for dependencies found only within those paths [2]. Scope: This setting is per-ecosystem, meaning you can tailor exclusions differently for `github-actions` versus other ecosystems like `npm` or `docker` [1][2]. Example usage in `dependabot.yml`: version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" exclude-paths: - "examples/" - ".github/workflows/experimental.yml" Note that `exclude-paths` is distinct from the `ignore` option [2]. While `exclude-paths` prevents Dependabot from even scanning specific files or directories, the `ignore` option is used to filter out specific dependency versions or update types for dependencies that are still being monitored [4][5][2]. You can use both in combination if needed [2].

Citations:


🌐 Web query:

GitHub Actions workflow security hardening pin actions to full length commit SHA tag based references v7.0.1

💡 Result:

Pinning GitHub Actions to a full-length commit SHA is considered the most secure practice for workflow hardening [1][2][3]. While tag-based references (like @v7.0.1) are common, they are mutable and can be moved or deleted, which introduces a security risk where the underlying code could be altered without your knowledge [1][2][3]. Key insights on hardening GitHub Actions: 1. Immutability via SHA Pinning: Pinning to a full-length (40-character) commit SHA ensures that the action remains immutable, meaning it will always execute the exact same code, regardless of changes to the source repository or tags [1][2][4]. 2. Security Risk of Tags: Tags (e.g., @v7.0.1) are pointers that can be reassigned by repository owners. If an action's repository is compromised, an attacker could point a legitimate-looking tag to malicious code, which your workflows would then automatically pull and execute [3][4]. 3. Balancing Security and Updates: You do not need to choose between security and maintainability. It is widely recommended to pin to the full-length commit SHA while including the human-readable version (e.g., @ # v7.0.1) as a trailing comment [3][4][5]. This allows dependency management tools like Dependabot or Renovate to track the version, identify updates, and open pull requests for you, maintaining both immutability and freshness [3][4]. 4. Enforced Policies: Organizations can now enforce full-length commit SHA pinning at the organization or repository level [1][6][7]. When this policy is enabled, workflows using tag-based references will fail, emphasizing the importance of transitioning to SHA pinning for compliance and defense-in-depth [6][7]. If you are using v7.0.1, you should identify the full commit SHA associated with that release tag in the source repository and update your workflow to use that SHA, ideally while retaining the version information in a comment for visibility [3][4][5].

Citations:


Keep the generated workflow actions immutable and covered by updates.

.github/workflows/dagger.yaml uses mutable action tags, but Dependabot is excluded from scanning this file, so generated tag-pinned actions can be left stale or bypass both immutability and update automation.

  • Pin the generated action references to full commit SHAs, with version comments where useful.
  • Remove the github-actions exclusion or add an equivalent generator-level action-update policy to keep pinning coverage complete.
🧰 Tools
🪛 zizmor (1.26.1)

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

(artipacked)

📍 Affects 2 files
  • .github/workflows/dagger.yaml#L8-L15 (this comment)
  • .github/dependabot.yaml#L26-L31
🤖 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/dagger.yaml around lines 8 - 15, Pin the generated action
references in .github/workflows/dagger.yaml at lines 8-15 to immutable full
commit SHAs, retaining version comments where useful for maintenance. Update
.github/dependabot.yaml at lines 26-31 to remove the github-actions exclusion,
or add an equivalent generator-level update policy, so all pinned workflow
actions remain covered by update automation.

Source: MCP tools

@sagikazarmark
sagikazarmark merged commit 54f6e24 into main Jul 26, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant