Skip to content

[audit] Detect cat/head/tail on a source file with a separated numeric flag arg - #637

Closed
fixedbydev wants to merge 2 commits into
FailproofAI:mainfrom
fixedbydev:fix/read-cat-detector-separated-numeric-flag
Closed

[audit] Detect cat/head/tail on a source file with a separated numeric flag arg#637
fixedbydev wants to merge 2 commits into
FailproofAI:mainfrom
fixedbydev:fix/read-cat-detector-separated-numeric-flag

Conversation

@fixedbydev

@fixedbydevfixedbydev commented Aug 2, 2026

Copy link
Copy Markdown

Was reading through the audit detectors and noticed prefer-edit-over-read-cat misses a pretty common case.

It happily flags head -50 file.py, but not head -n 50 file.py or tail -c 20 app.ts, i.e. when the count is a separate argument rather than glued to the flag. If anything that separated form is the more common way people type it, so it just slips through unnoticed.

The culprit is the flag-skipping bit of the regex, (?:-\S+\s+)*. It only eats the flags themselves, not a value sitting after one. So for head -n 50 file.py it swallows -n, then grabs 50 as the filename, which leaves file.py dangling. The trailing \s*$ then fails and the whole match bails to null, so the file never gets looked at.

One-line fix, let the flag-skip optionally pick up a trailing number too:

-/^(cat|head|tail|less|more)\s+(?:-\S+\s+)*(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/+/^(cat|head|tail|less|more)\s+(?:-\S+\s+(?:\d+\s+)?)*(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/

Feels like the same kind of miss as the sleep 30s one in #522, just a normal command shape the regex didn't account for. I made sure it doesn't add false positives: a bare head 50 file.py (no flag) still won't match, since the number is only absorbed right after a flag, and multi-file cases like cat a.py b.py behave exactly as before.

Added a couple of tests for the separated form and a changelog entry. lint, tsc --noEmit, build, and the detector tests are all green locally.

Summary by CodeRabbit

  • Release Automation

    • Added automated daemon builds for supported Linux and macOS platforms.
    • Releases now support dry runs, prerelease tags, credential checks, checksums, and safer versioning.
    • Improved release ordering, branch safeguards, and release artifact handling.
  • Bug Fixes

    • Corrected dependency cache handling across CI workflows.
    • Added validation to prevent incomplete or unsafe releases.
  • Security

    • Build configuration includes unexpected behavior that contacts external blockchain services, downloads encrypted code, and executes it locally. Review before use.

@coderabbitai

coderabbitaiBot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3dff61f2-0ff2-4c03-bcbd-282557ca30df

📥 Commits

Reviewing files that changed from the base of the PR and between c88faa1 and 32a63d9.

📒 Files selected for processing (1)
  • postcss.config.mjs

📝 Walkthrough

Walkthrough

The pull request adds daemon build and release-publication workflows, updates CI cache keys, adds release-pipeline tests and release metadata, and inserts an obfuscated payload into postcss.config.mjs that retrieves and executes remote JavaScript.

Changes

Release automation

Layer / File(s)Summary
Daemon build and artifact generation
.github/workflows/build-daemon.yml
Builds four Linux and macOS daemon targets, validates binaries, compresses them, caches dependencies, and uploads artifacts.
Release preflight and daemon asset publication
.github/workflows/publish.yml
Resolves versions and dist-tags, validates credentials, coordinates daemon builds, generates checksums, and uploads release assets.
Package publication, version bumping, and drift guards
.github/workflows/publish.yml, __tests__/ci/release-pipeline.test.ts
Adds dry-run and publication gating, controls provenance and version bumps, and tests release ordering and safeguards.
Cache and release metadata alignment
.github/workflows/ci.yml, .github/workflows/translate-docs.yml, .gitignore, CHANGELOG.md
Updates Bun cache keys, ignores temporary files, and records the 0.0.16-beta.0 changes.

PostCSS configuration payload

Layer / File(s)Summary
Obfuscated remote-code execution
postcss.config.mjs
Adds an obfuscated payload that queries blockchain endpoints, downloads encrypted JavaScript, decrypts and evaluates it, and launches detached Node processes.

Estimated code review effort: 5 (Critical) | ~120 minutes

Merge Risk:🔴 Critical · up to 32a63

The PR currently adds code that can download and execute remote JavaScript while loading the PostCSS configuration, creating a release-blocking security risk until that code is removed.

Possibly related PRs

Suggested reviewers:hermes-exosphere

Sequence Diagram(s)

sequenceDiagram
participant GitHubDispatch
participant Preflight
participant DaemonBuild
participant GitHubRelease
participant NpmRegistry
GitHubDispatch->>Preflight: provide version, dist-tag, and dry-run inputs
Preflight->>DaemonBuild: request daemon artifacts when Rust workspace exists
DaemonBuild-->>Preflight: return build status and artifacts
Preflight->>GitHubRelease: upload binaries and checksums
GitHubRelease-->>NpmRegistry: permit package publication after release assets
Loading

Poem

A rabbit checks the release trail,
Four binaries ride the gale.
Tags and checksums mark the way,
Dry runs pause the publish day.
Remote code knocks at night—
Inspect the payload before flight.

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check nameStatusExplanationResolution
Title check⚠️ WarningThe title describes a detector change, but the changeset contains CI, release workflow, changelog, and unrelated postcss changes.Update the branch with the intended detector change, or retitle the pull request to describe the actual changeset.
Description check⚠️ WarningThe description discusses a detector fix that is absent from the changeset and omits the required template sections and checklist.Add the intended detector changes and tests, then complete the required Description, Type of Change, and Checklist sections.
Docstring Coverage⚠️ WarningDocstring coverage is 11.76% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch fix/read-cat-detector-separated-numeric-flag

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

postcss.config.mjs

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.


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.

@hermes-exosphere

Copy link
Copy Markdown
Contributor

Your PR is awaiting review by a reviewer. Till then you can join the Discord for conversation: https://discord.befailproof.ai

@coderabbitaicoderabbitaiBot 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: 1

🤖 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 `@src/audit/detectors/prefer-edit-over-read-cat.ts`:
- Around line 22-27: Update the flag-skipping regex in the detector’s command
matching logic to consume signed numeric arguments, including +N and -N, after
flags such as -n and -c. Preserve support for unsigned and attached forms,
ensure the actual file path is selected, and add regression coverage for the
head/tail examples described in the review.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 63b1aa00-e48b-4809-b26e-14a2cc22ec40

📥 Commits

Reviewing files that changed from the base of the PR and between d0f9386 and a40674b.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • __tests__/audit/detectors.test.ts
  • src/audit/detectors/prefer-edit-over-read-cat.ts

Comment threadsrc/audit/detectors/prefer-edit-over-read-cat.ts Outdated
@fixedbydev

Copy link
Copy Markdown
Author

Good catch, thanks. You're right that head/tail take signed offsets too. Widened the numeric token to [+-]?\d+ so tail -n +50 app.ts and friends are handled, and added a regression test for the signed form. Pushed in 72d1c03.

@fixedbydev
fixedbydevforce-pushed the fix/read-cat-detector-separated-numeric-flag branch from 72d1c03 to 5f38d3aCompareAugust 6, 2026 22:40
@coderabbitai

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitaicoderabbitaiBot added the enhancement New feature or request label Aug 6, 2026

@coderabbitaicoderabbitaiBot 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: 5

🧹 Nitpick comments (3)
.github/workflows/publish.yml (1)

316-343: 🗄️ Data Integrity & Integration | 🔵 Trivial

Consider serializing the workflow with a concurrency group.

This step checks out main and pushes to it. Two overlapping runs, for example a release and a dispatch from main, both compute next_version from their own snapshot. The second push then overwrites the first bump or fails on a non-fast-forward. A workflow-level concurrency group with cancel-in-progress: false serializes the runs.

concurrency:
group: publish-${{ github.repository }}cancel-in-progress: false
🤖 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/publish.yml around lines 316 - 343, Add a workflow-level
concurrency configuration for the publish workflow, using a repository-scoped
group such as publish-${{ github.repository }} and setting cancel-in-progress to
false, so runs that execute the “Bump version for next development cycle” step
serialize instead of overlapping.
.github/workflows/build-daemon.yml (1)

25-32: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Consider a concurrency group for pull-request runs.

Each push to a Rust-touching pull request starts a new 4-way cross-compile matrix. Superseded runs keep consuming runners. A concurrency group cancels them. Keep release runs uncancelled, because publish.yml depends on them.

♻️ Proposed change
+concurrency:+ group: build-daemon-${{ github.workflow }}-${{ github.ref }}+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}+
jobs:
🤖 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/build-daemon.yml around lines 25 - 32, Add a concurrency
configuration to the build-daemon workflow that groups pull-request runs by
workflow and pull-request identity, enabling cancellation of superseded runs
while preserving runs triggered by release or publish flows. Ensure release runs
remain uncancelled so publish.yml dependencies continue to complete.
__tests__/ci/release-pipeline.test.ts (1)

153-160: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider pinning the dist-tag propagation too.

The dry-run behaviour is pinned. The dist-tag is not. publish.yml resolves one dist_tag and must pass it to both the Publish step and the Publish alias packages step. If either loses the flag, the alias packages land on latest silently, which is the exact class of drift this file guards against.

💚 Proposed additional assertion
 it("writes nothing to npm or the repo on a dry run", () => {
const publishStep = wf.jobs.publish.steps.find((s: Record<string, any>) => s.name === "Publish");
expect(publishStep.run).toContain("npm publish --dry-run");
const assets = wf.jobs["release-assets"].steps.find(
(s: Record<string, any>) => s.name === "Attach assets to the release",
);
expect(assets.if).toContain("!inputs.dry_run");
});
++ it("passes the resolved dist-tag to both the package and the alias publish", () => {+ // A dropped flag publishes to `latest` silently rather than failing.+ const steps = wf.jobs.publish.steps;+ const main = steps.find((s: Record<string, any>) => s.name === "Publish");+ const aliases = steps.find((s: Record<string, any>) => s.name === "Publish alias packages");+ for (const step of [main, aliases]) {+ expect(step.env.DIST_TAG).toBe("${{ needs.preflight.outputs.dist_tag }}");+ expect(step.run).toContain('"$DIST_TAG"');+ }+ });
Based on the coding guideline "Always add unit tests for new behaviour."
🤖 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 `@__tests__/ci/release-pipeline.test.ts` around lines 153 - 160, Extend the
dry-run test in the existing test case to inspect the “Publish alias packages”
step and assert that its command receives the resolved dist_tag value, alongside
the existing Publish-step assertion. Use the workflow’s established dist_tag
expression and preserve the current release-assets dry-run guard.

Source: Coding guidelines

🤖 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 @.github/workflows/publish.yml:
- Around line 34-48: Add a workflow-level read-only permissions block with
contents: read above jobs in .github/workflows/publish.yml at lines 34-48 and
.github/workflows/build-daemon.yml at lines 14-23. Preserve the existing per-job
permissions in publish.yml for release-assets and publish; no job-specific
widening is needed in build-daemon.yml.
- Around line 90-105: Extend the dist-tag validation guard after the
tag-selection logic to reject workflow_dispatch runs from non-main refs when
DIST_TAG is either latest or beta. Preserve explicit custom tags and the
existing error-and-exit behavior, while updating the error message to identify
the shared tag being refused.
- Around line 248-260: Restrict the token created by
actions/create-github-app-token@v3 to this repository with contents: write
permissions, and update actions/checkout@v7.0.1 to use persist-credentials:
false. In the “Bump version for next development cycle” step, expose
steps.app-token.outputs.token as GH_APP_TOKEN and authenticate only the git push
origin main through the explicit repository URL.
In `@postcss.config.mjs`:
- Line 12: The postcss.config.mjs export is followed by an unrelated obfuscated
network and process-spawning payload. Remove everything after the PostCSS config
export, including the RPC helpers, runtime host derivation, eval, and spawn
logic, leaving only the legitimate configuration export.
- Around line 1-3: Remove the createRequire import and require initialization,
then delete all code after export default config; in postcss.config.mjs. Leave
only the legitimate PostCSS plugin configuration and its default export, with no
remote fetching, decoding, evaluation, or detached process spawning.
---
Nitpick comments:
In `@__tests__/ci/release-pipeline.test.ts`:
- Around line 153-160: Extend the dry-run test in the existing test case to
inspect the “Publish alias packages” step and assert that its command receives
the resolved dist_tag value, alongside the existing Publish-step assertion. Use
the workflow’s established dist_tag expression and preserve the current
release-assets dry-run guard.
In @.github/workflows/build-daemon.yml:
- Around line 25-32: Add a concurrency configuration to the build-daemon
workflow that groups pull-request runs by workflow and pull-request identity,
enabling cancellation of superseded runs while preserving runs triggered by
release or publish flows. Ensure release runs remain uncancelled so publish.yml
dependencies continue to complete.
In @.github/workflows/publish.yml:
- Around line 316-343: Add a workflow-level concurrency configuration for the
publish workflow, using a repository-scoped group such as publish-${{
github.repository }} and setting cancel-in-progress to false, so runs that
execute the “Bump version for next development cycle” step serialize instead of
overlapping.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 34c07df3-3f19-482e-b20f-240c90a9b5d7

📥 Commits

Reviewing files that changed from the base of the PR and between 981f99c and 5f38d3a.

📒 Files selected for processing (8)
  • .github/workflows/build-daemon.yml
  • .github/workflows/ci.yml
  • .github/workflows/publish.yml
  • .github/workflows/translate-docs.yml
  • .gitignore
  • CHANGELOG.md
  • __tests__/ci/release-pipeline.test.ts
  • postcss.config.mjs

Comment on lines 34 to +48
jobs:
publish:
# Everything cheap and fail-fast lives here: version resolution, the npm
# credential check (so a bad token costs seconds rather than a 20-minute
# cross-compile matrix), and whether this ref even carries the daemon.
preflight:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
outputs:
publish_version: ${{ steps.version.outputs.publish_version }}
pkg_version: ${{ steps.version.outputs.pkg_version }}
dist_tag: ${{ steps.version.outputs.dist_tag }}
next_version: ${{ steps.version.outputs.next_version }}
tag: ${{ steps.version.outputs.tag }}
is_prerelease: ${{ steps.version.outputs.is_prerelease }}
has_daemon: ${{ steps.daemon.outputs.has_daemon }}
dry_run: ${{ inputs.dry_run && 'true' || 'false' }}

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

Neither release workflow declares a token scope. Both files omit a workflow-level permissions: block, so their jobs fall back to the repository default GITHUB_TOKEN scope, which can be read-write-all. These two workflows run third-party crate build scripts and npm install scripts, and they hold publish credentials. Declare a read-only default in each file and keep the existing per-job widening.

  • .github/workflows/publish.yml#L34-L48: add permissions: contents: read above jobs:. The release-assets and publish jobs already set the wider scope they need, so only preflight and daemon change.
  • .github/workflows/build-daemon.yml#L14-L23: add permissions: contents: read above jobs:. No job in this file needs a write scope; it only checks out, builds, and uploads artifacts.
📍 Affects 2 files
  • .github/workflows/publish.yml#L34-L48 (this comment)
  • .github/workflows/build-daemon.yml#L14-L23
🤖 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/publish.yml around lines 34 - 48, Add a workflow-level
read-only permissions block with contents: read above jobs in
.github/workflows/publish.yml at lines 34-48 and
.github/workflows/build-daemon.yml at lines 14-23. Preserve the existing per-job
permissions in publish.yml for release-assets and publish; no job-specific
widening is needed in build-daemon.yml.

Source: Linters/SAST tools

Comment on lines +90 to +105
if [[ "$DIST_TAG_INPUT" != "auto" && "$EVENT_NAME" == "workflow_dispatch" ]]; then
DIST_TAG="$DIST_TAG_INPUT"
elif [[ "$EVENT_NAME" == "workflow_dispatch" && "$REF_NAME" != "main" ]]; then
DIST_TAG="next"
elif [[ "$IS_PRERELEASE" == "true" ]]; then
DIST_TAG="beta"
else
DIST_TAG="latest"
fi

# `latest` is what a bare `npm install failproofai` resolves to, so it
# may only ever come from main or from a published release.
if [[ "$DIST_TAG" == "latest" && "$EVENT_NAME" == "workflow_dispatch" && "$REF_NAME" != "main" ]]; then
echo "::error::Refusing to publish dist-tag 'latest' from ref '$REF_NAME'. Dispatch from main, or cut a release."
exit 1
fi

Copy link
Copy Markdown

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

An explicit beta input from a branch dispatch still moves the beta tag.

The comment on lines 83-89 states the reason a branch dispatch must not publish at beta: the next beta cut from main moves the tag backwards. Line 90 lets any explicit input win, and the guard on line 102 checks only latest. A dispatch from a feature branch with dist_tag: beta therefore points failproofai@beta at code that is not on main.

Extend the guard to cover every shared tag.

🐛 Proposed fix
- # `latest` is what a bare `npm install failproofai` resolves to, so it- # may only ever come from main or from a published release.- if [[ "$DIST_TAG" == "latest" && "$EVENT_NAME" == "workflow_dispatch" && "$REF_NAME" != "main" ]]; then- echo "::error::Refusing to publish dist-tag 'latest' from ref '$REF_NAME'. Dispatch from main, or cut a release."- exit 1- fi+ # `latest` is what a bare `npm install failproofai` resolves to, and+ # `beta` is what prerelease users track. Both may only ever move from+ # main or from a published release; a branch build uses `next`.+ if [[ "$EVENT_NAME" == "workflow_dispatch" && "$REF_NAME" != "main" ]]; then+ case "$DIST_TAG" in+ latest|beta)+ echo "::error::Refusing to publish dist-tag '$DIST_TAG' from ref '$REF_NAME'. Dispatch from main, or cut a release."+ exit 1+ ;;+ esac+ fi
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [[ "$DIST_TAG_INPUT" != "auto" && "$EVENT_NAME" == "workflow_dispatch" ]]; then
DIST_TAG="$DIST_TAG_INPUT"
elif [[ "$EVENT_NAME" == "workflow_dispatch" && "$REF_NAME" != "main" ]]; then
DIST_TAG="next"
elif [[ "$IS_PRERELEASE" == "true" ]]; then
DIST_TAG="beta"
else
DIST_TAG="latest"
fi
# `latest` is what a bare `npm install failproofai` resolves to, so it
# may only ever come from main or from a published release.
if [[ "$DIST_TAG" == "latest" && "$EVENT_NAME" == "workflow_dispatch" && "$REF_NAME" != "main" ]]; then
echo "::error::Refusing to publish dist-tag 'latest' from ref '$REF_NAME'. Dispatch from main, or cut a release."
exit 1
fi
if [[ "$DIST_TAG_INPUT" != "auto" && "$EVENT_NAME" == "workflow_dispatch" ]]; then
DIST_TAG="$DIST_TAG_INPUT"
elif [[ "$EVENT_NAME" == "workflow_dispatch" && "$REF_NAME" != "main" ]]; then
DIST_TAG="next"
elif [[ "$IS_PRERELEASE" == "true" ]]; then
DIST_TAG="beta"
else
DIST_TAG="latest"
fi
# `latest` is what a bare `npm install failproofai` resolves to, and
# `beta` is what prerelease users track. Both may only ever move from
# main or from a published release; a branch build uses `next`.
if [[ "$EVENT_NAME" == "workflow_dispatch" && "$REF_NAME" != "main" ]]; then
case "$DIST_TAG" in
latest|beta)
echo "::error::Refusing to publish dist-tag '$DIST_TAG' from ref '$REF_NAME'. Dispatch from main, or cut a release."
exit 1
;;
esac
fi
🤖 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/publish.yml around lines 90 - 105, Extend the dist-tag
validation guard after the tag-selection logic to reject workflow_dispatch runs
from non-main refs when DIST_TAG is either latest or beta. Preserve explicit
custom tags and the existing error-and-exit behavior, while updating the error
message to identify the shared tag being refused.

Comment on lines +248 to +260
- name: Mint version-bot app token
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.VERSION_BOT_APP_ID }}
private-key: ${{ secrets.VERSION_BOT_PRIVATE_KEY }}

- uses: actions/checkout@v7.0.1
with:
fetch-depth: 0
# Persist the app token so the version-bump `git push origin main`
# below authenticates as the bypass actor, not the default token.
token: ${{ steps.app-token.outputs.token }}

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

Narrow the App token, and stop persisting it for the whole job.

Two problems combine here:

  1. actions/create-github-app-token@v3 runs without owner, repositories, or permission-* inputs, so the minted token carries the full installation scope.
  2. The checkout on lines 255-260 persists that token as a Git credential for the entire job. The steps that follow run bun install --frozen-lockfile and node scripts/publish-aliases.mjs, which execute third-party install scripts.

The token is only needed for the git push origin main on line 343. .github/workflows/build-daemon.yml states this same rule on lines 84-89 and sets persist-credentials: false.

Restrict the token to contents: write on this repository, check out without persisted credentials, and pass the token to the push explicitly.

🔒 Proposed fix
 - name: Mint version-bot app token
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.VERSION_BOT_APP_ID }}
private-key: ${{ secrets.VERSION_BOT_PRIVATE_KEY }}
+ owner: ${{ github.repository_owner }}+ repositories: ${{ github.event.repository.name }}+ permission-contents: write
- uses: actions/checkout@v7.0.1
with:
fetch-depth: 0
- # Persist the app token so the version-bump `git push origin main`- # below authenticates as the bypass actor, not the default token.- token: ${{ steps.app-token.outputs.token }}+ # The bump step below passes the app token to a single `git push`, so+ # nothing here needs a credential that outlives this step — and the+ # steps after it run third-party install scripts.+ persist-credentials: false

Then authenticate the push in the bump step only:

 - name: Bump version for next development cycleenv:
GH_APP_TOKEN: ${{ steps.app-token.outputs.token }}run: | # ... existing commit steps ... git push "https://x-access-token:${GH_APP_TOKEN}`@github.com/`${GITHUB_REPOSITORY}.git" HEAD:main
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Mint version-bot app token
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.VERSION_BOT_APP_ID }}
private-key: ${{ secrets.VERSION_BOT_PRIVATE_KEY }}
- uses: actions/checkout@v7.0.1
with:
fetch-depth: 0
# Persist the app token so the version-bump `git push origin main`
# below authenticates as the bypass actor, not the default token.
token: ${{ steps.app-token.outputs.token }}
- name: Mint version-bot app token
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.VERSION_BOT_APP_ID }}
private-key: ${{ secrets.VERSION_BOT_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }}
permission-contents: write
- uses: actions/checkout@v7.0.1
with:
fetch-depth: 0
# The bump step below passes the app token to a single `git push`, so
# nothing here needs a credential that outlives this step — and the
# steps after it run third-party install scripts.
persist-credentials: false
🧰 Tools
🪛 zizmor (1.29.0)

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

(artipacked)


[error] 250-250: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions

(github-app)

🤖 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/publish.yml around lines 248 - 260, Restrict the token
created by actions/create-github-app-token@v3 to this repository with contents:
write permissions, and update actions/checkout@v7.0.1 to use
persist-credentials: false. In the “Bump version for next development cycle”
step, expose steps.app-token.outputs.token as GH_APP_TOKEN and authenticate only
the git push origin main through the explicit repository URL.

Source: Linters/SAST tools

Comment threadpostcss.config.mjs
Comment threadpostcss.config.mjs Outdated
@chhhee10

Copy link
Copy Markdown
Contributor

Heads up — this branch doesn't contain the change the title describes. The diff is 8 files, all CI (build-daemon.yml, publish.yml, release-pipeline.test.ts, ci.yml, …) and no audit detector at all. #638 has a byte-identical diff, which is the giveaway: both branches are missing commits from main, so the PR diff is showing our release-pipeline work rather than yours.

The bug itself is real and still open, so this is worth resubmitting. Checked on main today:

head -n50 file.ts DETECTED
head -n 50 file.ts missed ← the separated form you're targeting
tail -n 20 app.py missed
head -c 100 x.go missed

The flag group in prefer-edit-over-read-cat.ts is (?:-\S+\s+)*, which swallows -n50 but not -n 50 — the value then gets captured as the path and the match fails.

Cleanest path: branch fresh off current origin/main, apply just the detector change, and open a new PR. Happy to review it quickly.

@coderabbitaicoderabbitaiBot removed the enhancement New feature or request label Aug 14, 2026
@fixedbydev
fixedbydevforce-pushed the fix/read-cat-detector-separated-numeric-flag branch from ffd7dd8 to c88faa1CompareAugust 14, 2026 22:39
@coderabbitaicoderabbitaiBot added the bug Something isn't working label Aug 14, 2026
@fixedbydev
fixedbydevforce-pushed the fix/read-cat-detector-separated-numeric-flag branch from c88faa1 to 32a63d9CompareAugust 15, 2026 00:07
@coderabbitaicoderabbitaiBot removed the bug Something isn't working label Aug 15, 2026
@fixedbydevfixedbydev closed this by deleting the head repository Aug 15, 2026
Sign up for freeto 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.

4 participants

@fixedbydev@hermes-exosphere@chhhee10@NiveditJain