Skip to content

ci: fix cargo-geiger unsafe check#92

Merged
27Bslash6 merged 5 commits intomainfrom
fix/security-medium-geiger
Apr 24, 2026
Merged

ci: fix cargo-geiger unsafe check#92
27Bslash6 merged 5 commits intomainfrom
fix/security-medium-geiger

Conversation

@27Bslash6
Copy link
Copy Markdown
Contributor

@27Bslash6 27Bslash6 commented Apr 24, 2026

Summary

  • Fix wrong jq paths (.package.functions vs .unsafety.used.functions.unsafe_)
  • Remove bc dependency (not installed on runner)
  • Scope check to cachekit-rs only — all-deps check is meaningless since crypto crates (ring, aes-gcm) are inherently unsafe
  • Zero unsafe functions in our crate is the correct invariant

Test plan

  • Security Medium workflow passes on merge to main

Summary by CodeRabbit

  • Chores
    • Enhanced security validation in CI/CD workflows to enforce stricter unsafe code standards.

Note: This is an internal infrastructure change with no direct user-facing impact.

Wrong jq paths (.package.functions vs .unsafety.used.functions) produced
null, and bc isn't on the runner. Replaced with correct paths and scoped
check to cachekit-rs only — checking all deps is meaningless since crypto
crates (ring, aes-gcm) are inherently unsafe.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 24, 2026

Warning

Rate limit exceeded

@27Bslash6 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 38 minutes and 54 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 38 minutes and 54 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c8fefd78-5db8-413f-ad38-23b90775c9bb

📥 Commits

Reviewing files that changed from the base of the PR and between 7522872 and 42ff95a.

📒 Files selected for processing (7)
  • .github/workflows/security-medium.yml
  • src/cachekit/config/validation.py
  • src/cachekit/decorators/wrapper.py
  • tests/integration/test_redis_integration.py
  • tests/unit/backends/test_file_backend.py
  • tests/unit/test_encryption_config_validation.py
  • tests/unit/test_l1_only_mode.py
📝 Walkthrough

Walkthrough

The GitHub Actions security workflow is modified to replace a global unsafe-function ratio threshold with a stricter per-crate enforcement, specifically requiring zero unsafe functions in the cachekit-rs package. The unsafe-code gate now directly inspects that package's unsafe function count instead of calculating ratios across all packages.

Changes

Cohort / File(s) Summary
Workflow Security Gate
.github/workflows/security-medium.yml
Changed unsafe-code validation from enforcing a global ≤5% unsafe-function ratio across all geiger-reported packages to requiring exactly zero unsafe functions in the cachekit-rs package. Removed ratio calculation and reporting logic, updated gate failure conditions and messaging.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 No unsafe code shall pass this gate,
One crate to check, we zero-wait,
From ratios loose to strict and true,
Security tightens, bright and new! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description lacks required template sections like Type of Change, Security Checklist, and Testing sections that are mandatory per the repository template. Add the missing template sections (Type of Change, Security Checklist, and Testing) with appropriate selections and checkboxes to comply with repository standards.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: fixing the cargo-geiger unsafe code check in CI.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/security-medium-geiger

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
.github/workflows/security-medium.yml (1)

43-48: Harden the jq lookup against a missing cachekit-rs entry in the geiger report.

When the select(.package.id.name == "cachekit-rs") predicate matches nothing (e.g., if the crate is removed, renamed, or the geiger report schema changes), UNSAFE_FUNCS becomes an empty string and the arithmetic comparison [ "$UNSAFE_FUNCS" -ne 0 ] fails with a cryptic bash error (integer expression expected) instead of an actionable diagnostic. The job still exits with failure (as intended), but the error message won't make the cause obvious.

Add a pre-check to validate the lookup succeeded and produce a clear failure message:

Proposed hardening
-        UNSAFE_FUNCS=$(jq '.packages[] | select(.package.id.name == "cachekit-rs") | .unsafety.used.functions.unsafe_' geiger-report.json)
-        echo "cachekit-rs unsafe functions: $UNSAFE_FUNCS"
-        if [ "$UNSAFE_FUNCS" -ne 0 ]; then
-          echo "cachekit-rs has $UNSAFE_FUNCS unsafe functions — must be zero"
-          exit 1
-        fi
+        UNSAFE_FUNCS=$(jq -r 'first(.packages[] | select(.package.id.name == "cachekit-rs") | .unsafety.used.functions.unsafe_) // empty' geiger-report.json)
+        if [ -z "$UNSAFE_FUNCS" ]; then
+          echo "cachekit-rs package not found in geiger report"
+          exit 1
+        fi
+        echo "cachekit-rs unsafe functions: $UNSAFE_FUNCS"
+        if [ "$UNSAFE_FUNCS" -ne 0 ]; then
+          echo "cachekit-rs has $UNSAFE_FUNCS unsafe functions — must be zero"
+          exit 1
+        fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/security-medium.yml around lines 43 - 48, The current jq
lookup for UNSAFE_FUNCS can produce an empty string if select(.package.id.name
== "cachekit-rs") finds nothing, causing the numeric test [ "$UNSAFE_FUNCS" -ne
0 ] to fail with a cryptic error; update the logic that sets UNSAFE_FUNCS (the
jq select on geiger-report.json) to first detect a missing result and fail with
a clear message, e.g., check if UNSAFE_FUNCS is empty (test -z "$UNSAFE_FUNCS"
or use jq to provide a null/default) and if so echo a descriptive error like
"cachekit-rs entry missing in geiger-report.json" and exit 1; otherwise proceed
to the numeric comparison of UNSAFE_FUNCS against 0.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.github/workflows/security-medium.yml:
- Around line 43-48: The current jq lookup for UNSAFE_FUNCS can produce an empty
string if select(.package.id.name == "cachekit-rs") finds nothing, causing the
numeric test [ "$UNSAFE_FUNCS" -ne 0 ] to fail with a cryptic error; update the
logic that sets UNSAFE_FUNCS (the jq select on geiger-report.json) to first
detect a missing result and fail with a clear message, e.g., check if
UNSAFE_FUNCS is empty (test -z "$UNSAFE_FUNCS" or use jq to provide a
null/default) and if so echo a descriptive error like "cachekit-rs entry missing
in geiger-report.json" and exit 1; otherwise proceed to the numeric comparison
of UNSAFE_FUNCS against 0.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6d26c3ec-22a6-4f42-83f5-d4f3e6f6af84

📥 Commits

Reviewing files that changed from the base of the PR and between 50c8fe0 and 7522872.

📒 Files selected for processing (1)
  • .github/workflows/security-medium.yml

- test_exists_expired_ttl: TTL 1s→2s, sleep 1.5s→2.5s (1s expired
  between set() and exists() under CI load)
- test_concurrent_access: move asyncio.Lock() inside async function
  (Python 3.9 requires a running event loop for Lock constructor)
If cachekit-rs isn't found in the geiger report, jq returns empty
string and the numeric comparison blows up. Fail cleanly instead.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 24, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

validate_encryption_config() reads CACHEKIT_MASTER_KEY from the
pydantic-settings singleton. If a prior test already cached the
singleton without the key, setting the env var has no effect.
Must reset_settings() after setting env var and in finally cleanup.
The validator was checking CACHEKIT_MASTER_KEY env var via the
pydantic-settings singleton, ignoring the master_key passed directly
to @cache.secure(master_key=...). This caused flaky test failures
depending on singleton cache state.

Now: explicit master_key param takes precedence over env var.
Production warning only fires when key came from env var (not inline).
@27Bslash6 27Bslash6 merged commit 7d5db7f into main Apr 24, 2026
32 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