Skip to content

chore(security): dependency-review, invisible-char detection, and least-privilege workflow permissions (#782)#783

Open
edelauna wants to merge 3 commits into
mainfrom
issue/782
Open

chore(security): dependency-review, invisible-char detection, and least-privilege workflow permissions (#782)#783
edelauna wants to merge 3 commits into
mainfrom
issue/782

Conversation

@edelauna

@edelauna edelauna commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Related GitHub Issue

Closes: #782

Description

Implements the in-repo supply-chain hardening from #782. Complements #781 (publish provenance); this PR does not touch publish workflows.

Changes:

  • Dependency review on PRs (code-qa.yml) — new dependency-review job, gated on pull_request events, validates the dependency diff of a PR against GitHub's advisory database before merge. actions/dependency-review-action@v5.0.0, pinned by SHA.
  • Invisible / homoglyph Unicode detection — two layers:
    • ESLint no-irregular-whitespace (error, skipStrings: true) added to the shared packages/config-eslint/base.js, so every workspace inherits it. Local fast feedback for identifier/token splitting; skipStrings: true keeps it quiet in i18n locale files.
    • New invisible-chars CI job in code-qa.yml — the authoritative defense. Scans raw bytes (so it catches chars in strings, identifiers, and comments alike) for zero-width (U+200B–200F), word joiner (U+2060), BOM (U+FEFF), bidi-override / "Trojan Source" (U+202A–202E), and soft hyphen (U+00AD). Covers *.ts/.tsx/.js/.mjs/.cjs/.cts/.mts/.sh and the executable run: blocks inside .github workflow/action YAML.
  • Least-privilege permissions: contents: read added as a top-level default to the 6 workflows that were missing it (code-qa, cli-release, codeql, e2e, marketplace-publish, release-validation). Jobs that need more (e.g. release, publish-stable, CodeQL analyze) keep their existing job-level escalation.
  • .vscode/settings.json cleanup — enabled editor.unicodeHighlight.invisibleCharacters + ambiguousCharacters; replaced the deprecated typescript.tsc.autoDetect with js/ts.tsc.autoDetect; removed the unresolved vitest.disableWorkspaceWarning (the Vitest extension isn't in workspace recommendations, so it produced "unknown setting" noise for most contributors).

Already good (not changed here): all third-party actions are SHA-pinned, --frozen-lockfile is universal, and pnpm's onlyBuiltDependencies allowlist already blocks arbitrary install scripts.

Test Procedure

  • pnpm --filter ./src lint, pnpm --filter ./webview-ui lint, pnpm --filter @roo-code/core lint — all pass with --max-warnings=0 (the new ESLint rule produces zero violations against existing code).
  • Ran the exact CI grep command locally against the expanded scope (src webview-ui packages apps .github, all listed extensions) → zero matches (no false positives).
  • Self-test: planted a zero-width char in both a .sh and a .yml; the CI grep correctly detected both, then removed the planted files (working tree verified clean).
  • All 6 edited workflows validated as YAML.

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I have performed a thorough self-review of my code.
  • Testing: New and/or updated tests have been added to cover my changes (if applicable).
  • Documentation Impact: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Screenshots / Videos

N/A — CI/config only, no UI changes.

Documentation Updates

  • No documentation updates are required.

Additional Notes

A code review flagged that the original invisible-char scan missed executable release scripts (*.sh/*.cjs) and workflow/action YAML; this is addressed — the scan now covers both.

One review suggestion (re-adding vitest.disableWorkspaceWarning) was intentionally not applied: the Vitest extension is not in workspace recommendations, so the setting is unresolved for most contributors and only adds "unknown setting" noise. If the workspace-config warning becomes painful for contributors using the Vitest GUI extension, the cleaner fix is to add vitest.explorer to .vscode/extensions.json.

Get in Touch

Summary by CodeRabbit

  • New Features
    • Added CI checks to detect invisible/ambiguous Unicode characters in tracked files.
    • Updated editor settings to highlight invisible and ambiguous Unicode characters.
  • Bug Fixes
    • Enforced least-privilege default permissions for multiple CI and release workflows.
    • Strengthened linting to reject irregular/invisible Unicode whitespace in code.
  • Chores
    • Added an automated dependency review step for pull requests to surface risky dependency changes early.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 242ba6ca-d0a1-450d-9167-fca52e263c6e

📥 Commits

Reviewing files that changed from the base of the PR and between bcfc948 and 6b06fd1.

📒 Files selected for processing (2)
  • .github/workflows/code-qa.yml
  • packages/config-eslint/base.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/code-qa.yml
  • packages/config-eslint/base.js

📝 Walkthrough

Walkthrough

This PR adds dependency-review and invisible-character scanning to CI, applies least-privilege permissions defaults to six workflows, and updates editor and ESLint settings to surface invisible Unicode characters locally.

Changes

Security Hardening

Layer / File(s) Summary
Dependency-review and invisible-char CI jobs
.github/workflows/code-qa.yml
Adds a pull-request-only dependency-review job and an invisible-chars job that scans selected paths and file types for invisible or homoglyph Unicode characters and fails on matches.
Least-privilege permissions across workflows
.github/workflows/cli-release.yml, .github/workflows/code-qa.yml, .github/workflows/codeql.yml, .github/workflows/e2e.yml, .github/workflows/marketplace-publish.yml, .github/workflows/release-validation.yml
Adds top-level permissions: contents: read blocks to six workflows, leaving existing job-level escalations intact.
Local invisible-character detection tooling
.vscode/settings.json, packages/config-eslint/base.js
Updates VS Code Unicode highlighting settings and enables the no-irregular-whitespace ESLint rule with string and regex exclusions.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main security-hardening changes in this PR.
Description check ✅ Passed The description includes the linked issue, change summary, test procedure, checklist, and extra context.
Linked Issues check ✅ Passed The PR implements dependency review, invisible-character detection, and least-privilege permissions as required by #782.
Out of Scope Changes check ✅ Passed The changes stay within the security-hardening scope and include no unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 issue/782

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.

@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@edelauna edelauna changed the title deps: updating security posture in ci chore(security): dependency-review, invisible-char detection, and least-privilege workflow permissions (#782) Jul 1, 2026
@edelauna edelauna marked this pull request as ready for review July 1, 2026 15:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/config-eslint/base.js (1)

42-50: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Rule only covers a subset of invisible/homoglyph characters — comment slightly overstates coverage.

no-irregular-whitespace's character set covers \u200B (ZWSP) and \uFEFF (BOM), but not zero-width joiner/non-joiner (\u200C/\u200D), word joiner (\u2060), soft hyphen (\u00AD), or the bidi-override/Trojan Source characters (\u202A\u202E, \u2066\u2069). So even with skipStrings: true, this local rule won't catch those in identifiers/comments/code — only the CI invisible-chars byte-scan job (per the PR description) covers that full set. Worth tightening the comment so contributors don't over-rely on the editor/lint layer for Trojan Source protection.

Suggested comment tweak
-			// Reject invisible/irregular whitespace (zero-width chars, etc.) in
-			// identifiers and between tokens. String literals are skipped to
-			// avoid noise in i18n locale files; the CI invisible-chars job in
-			// code-qa.yml is the authoritative defense for the string case
-			// (it scans raw bytes across strings, identifiers, and comments).
+			// Reject irregular whitespace (incl. zero-width space \u200B and BOM)
+			// in identifiers and between tokens. This rule does NOT catch
+			// bidi-override, ZWJ/ZWNJ, or word-joiner characters; the CI
+			// invisible-chars job in code-qa.yml is the authoritative defense
+			// for the full Trojan Source character set across all files.
🤖 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 `@packages/config-eslint/base.js` around lines 42 - 50, Tighten the explanatory
comment above the no-irregular-whitespace rule in base.js so it does not claim
broader invisible/homoglyph coverage than the rule actually provides. Keep the
note around the rule itself, but make clear that no-irregular-whitespace only
handles its limited whitespace set and that the CI invisible-chars job in
code-qa.yml is what covers the wider Trojan Source/invisible-character cases;
update the wording near skipStrings and skipComments accordingly.
🤖 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/code-qa.yml:
- Around line 28-55: Add a pre-merge safety check for the new invisible-chars
gate and harden Checkout by setting persist-credentials: false in the
invisible-chars job. The grep in the run step currently scans for ZWJ/RLM/LRM
and bidi characters across source and workflow files with no exceptions, so
verify the current main branch yields zero matches before enabling it, or the
job will fail on existing legitimate i18n/emoji content. Update the
actions/checkout step and, if needed, narrow the grep pattern or exclusions in
the invisible-chars job to avoid false positives while keeping the scan
effective.

---

Nitpick comments:
In `@packages/config-eslint/base.js`:
- Around line 42-50: Tighten the explanatory comment above the
no-irregular-whitespace rule in base.js so it does not claim broader
invisible/homoglyph coverage than the rule actually provides. Keep the note
around the rule itself, but make clear that no-irregular-whitespace only handles
its limited whitespace set and that the CI invisible-chars job in code-qa.yml is
what covers the wider Trojan Source/invisible-character cases; update the
wording near skipStrings and skipComments accordingly.
🪄 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: 0983a405-70f8-418d-baf7-8749004b8703

📥 Commits

Reviewing files that changed from the base of the PR and between f845f2a and bcfc948.

📒 Files selected for processing (8)
  • .github/workflows/cli-release.yml
  • .github/workflows/code-qa.yml
  • .github/workflows/codeql.yml
  • .github/workflows/e2e.yml
  • .github/workflows/marketplace-publish.yml
  • .github/workflows/release-validation.yml
  • .vscode/settings.json
  • packages/config-eslint/base.js

Comment thread .github/workflows/code-qa.yml
@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 1, 2026
@github-actions github-actions Bot added awaiting-review PR changes are ready and waiting for maintainer re-review and removed awaiting-review PR changes are ready and waiting for maintainer re-review labels Jul 1, 2026
@github-actions github-actions Bot added awaiting-review PR changes are ready and waiting for maintainer re-review and removed awaiting-review PR changes are ready and waiting for maintainer re-review labels Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-review PR changes are ready and waiting for maintainer re-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore(security): dependency-review, invisible-char detection, and least-privilege workflow permissions

2 participants