fix(security): CodeQL icons literals + pnpm overrides for advisories#40
Conversation
📝 WalkthroughWalkthroughAdds documentation for LeanIX ↔ Draw.io bridge workflows and MCP scope, introduces a utility to harden JSON string literals used in vite-plugin virtuals (with tests and integration), and updates root pnpm.overrides and CI workflow permissions and gitignore patterns. Changes
Sequence Diagram(s)sequenceDiagram
participant Dev as Developer (CLI)
participant CLI as likec4 CLI
participant MCP as MCP Server / likec4:mcp
participant LeanIX as LeanIX API
participant Drawio as Draw.io
Dev->>CLI: bunx likec4 gen leanix --dry-run
CLI->>CLI: produce LeanIX manifest (with likec4 IDs)
Dev->>CLI: bunx likec4 sync leanix --dry-run / --apply (with LEANIX_API_TOKEN)
CLI->>LeanIX: sync manifest (dry-run/apply)
Dev->>CLI: bunx likec4 export --profile leanix --to drawio
CLI->>Drawio: export Draw.io XML (bridge-managed ids)
Dev->>CLI: bunx likec4 parse drawio (round-trip)
CLI->>CLI: manifestToDrawioLeanixMapping(manifest) -> map identifiers
Dev->>MCP: likec4 mcp (query/search) // read-only model access
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/vite-plugin/src/virtuals/hardenJsonStringLiteralForEmbeddedScript.ts (1)
9-16: Optional: add a contract guard to catch accidental non-JSON-literal inputs.A tiny precondition can prevent misuse in future call sites.
Suggested defensive check
export function hardenJsonStringLiteralForEmbeddedScript(jsonStringified: string): string { + if (!(jsonStringified.startsWith('"') && jsonStringified.endsWith('"'))) { + throw new Error('Expected a JSON.stringify(...) string literal input') + } return jsonStringified .replace(/</g, '\\u003C') .replace(/>/g, '\\u003E') .replace(/\//g, '\\u002F') .replace(/\u2028/g, '\\u2028') .replace(/\u2029/g, '\\u2029') }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/vite-plugin/src/virtuals/hardenJsonStringLiteralForEmbeddedScript.ts` around lines 9 - 16, Add a defensive contract guard to hardenJsonStringLiteralForEmbeddedScript: verify the input is a string (typeof jsonStringified === 'string') and sanity-check that it looks like a JSON literal (e.g. starts with '"', '{', '[' or matches /^-?\d|^(true|false|null)/); if the check fails throw a clear TypeError mentioning hardenJsonStringLiteralForEmbeddedScript so misuse is caught early. This keeps the existing replacements but prevents accidental non-JSON-literal inputs from being silently processed.packages/vite-plugin/src/virtuals/icons.ts (1)
101-109: Recommended follow-up: apply the same hardening to other virtual codegen sinks.You still have direct
JSON.stringify(...)embedding in:
packages/vite-plugin/src/virtuals/_shared.ts(lines 88-93),packages/vite-plugin/src/virtuals/single-project.ts(lines 4-14),packages/vite-plugin/src/virtuals/mmd.ts(lines 26-30).Using the same helper there would make this mitigation consistent.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/vite-plugin/src/virtuals/icons.ts` around lines 101 - 109, Other virtual codegen sinks still embed JSON via direct JSON.stringify; update them to use the same hardening helper as used here: replace JSON.stringify(...) embeddings with hardenJsonStringLiteralForEmbeddedScript(embed...AsJsString(...)) calls (reusing embedProjectIdAsJsString/embedUrlAsJsString where appropriate) so the generated literals are hardened before injecting into code; check the virtual generators mentioned (virtuals/_shared.ts, virtuals/single-project.ts, virtuals/mmd.ts) and swap the raw JSON.stringify usages for hardenJsonStringLiteralForEmbeddedScript wrapping the corresponding embed*AsJsString helpers, keeping the import usage consistent with joinURL and IconRenderer patterns already used in icons.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@packages/vite-plugin/src/virtuals/hardenJsonStringLiteralForEmbeddedScript.ts`:
- Around line 9-16: Add a defensive contract guard to
hardenJsonStringLiteralForEmbeddedScript: verify the input is a string (typeof
jsonStringified === 'string') and sanity-check that it looks like a JSON literal
(e.g. starts with '"', '{', '[' or matches /^-?\d|^(true|false|null)/); if the
check fails throw a clear TypeError mentioning
hardenJsonStringLiteralForEmbeddedScript so misuse is caught early. This keeps
the existing replacements but prevents accidental non-JSON-literal inputs from
being silently processed.
In `@packages/vite-plugin/src/virtuals/icons.ts`:
- Around line 101-109: Other virtual codegen sinks still embed JSON via direct
JSON.stringify; update them to use the same hardening helper as used here:
replace JSON.stringify(...) embeddings with
hardenJsonStringLiteralForEmbeddedScript(embed...AsJsString(...)) calls (reusing
embedProjectIdAsJsString/embedUrlAsJsString where appropriate) so the generated
literals are hardened before injecting into code; check the virtual generators
mentioned (virtuals/_shared.ts, virtuals/single-project.ts, virtuals/mmd.ts) and
swap the raw JSON.stringify usages for hardenJsonStringLiteralForEmbeddedScript
wrapping the corresponding embed*AsJsString helpers, keeping the import usage
consistent with joinURL and IconRenderer patterns already used in icons.ts.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c67d3164-316d-4170-a5f5-8eba30071897
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (12)
.changeset/leanix-bridge-skills-mcp-docs.md.changeset/security-icons-codeql-lockfile.md.gitignoreAGENTS.mdpackage.jsonpackages/mcp/README.mdpackages/vite-plugin/src/virtuals/hardenJsonStringLiteralForEmbeddedScript.spec.tspackages/vite-plugin/src/virtuals/hardenJsonStringLiteralForEmbeddedScript.tspackages/vite-plugin/src/virtuals/icons.tsskills/likec4-dsl/SKILL.mdskills/likec4-dsl/references/bridge-leanix-drawio.mdskills/likec4-dsl/references/cli.md
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/checks.yaml:
- Around line 6-9: Remove the unnecessary actions: write permission from the
workflow permissions block; keep contents: read for actions/checkout, and ensure
that artifact steps (actions/upload-artifact@v6, actions/download-artifact@v7)
and external Cloudflare Wrangler use their existing tokens/APIs without
requiring actions: write—so delete the line containing "actions: write" in the
permissions block to enforce least privilege.
🪄 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
Run ID: e4babd49-8763-449b-aadc-931a1c674ffa
📒 Files selected for processing (7)
.github/workflows/checks.yaml.github/workflows/ci-pr.yaml.github/workflows/codeql.yml.github/workflows/issue-comment.yaml.github/workflows/pkg-pr-new.yaml.github/workflows/push.yaml.github/workflows/trigger-deploy-template.yaml
✅ Files skipped from review due to trivial changes (3)
- .github/workflows/push.yaml
- .github/workflows/trigger-deploy-template.yaml
- .github/workflows/ci-pr.yaml
| permissions: | ||
| contents: read | ||
| actions: write | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if any step in this workflow or called actions use GitHub Actions API endpoints requiring write access
# Look for any cancel, re-run, or workflow management operations
rg -n 'cancel|re-run|workflow.*run|actions/stale' .github/workflows/checks.yaml
# Check if turbo or any tooling might need actions:write for caching
rg -n 'cache|turbo' .github/workflows/checks.yaml
# Check if the bootstrap action might require actions:write
cat .github/actions/bootstrap/action.yaml 2>/dev/null || cat .github/actions/bootstrap/action.yml 2>/dev/nullRepository: sraphaz/likec4
Length of output: 1032
🏁 Script executed:
cat -n .github/workflows/checks.yaml | head -250Repository: sraphaz/likec4
Length of output: 7668
Remove the unnecessary actions: write permission.
The contents: read permission is required for actions/checkout. However, actions: write is not used anywhere in this workflow. The artifact upload/download operations (actions/upload-artifact@v6, actions/download-artifact@v7) use the built-in artifacts API and do not require this permission. The Cloudflare Wrangler action uses an external API token, and the conditional !cancelled() check is purely informational. Removing this permission follows the principle of least privilege:
Suggested change
permissions:
contents: read
- actions: write📝 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.
| permissions: | |
| contents: read | |
| actions: write | |
| permissions: | |
| contents: read |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/checks.yaml around lines 6 - 9, Remove the unnecessary
actions: write permission from the workflow permissions block; keep contents:
read for actions/checkout, and ensure that artifact steps
(actions/upload-artifact@v6, actions/download-artifact@v7) and external
Cloudflare Wrangler use their existing tokens/APIs without requiring actions:
write—so delete the line containing "actions: write" in the permissions block to
enforce least privilege.
Apply uncle-bob boundary: one policy surface (root overrides) plus small harden helper + tests. pnpm audit: only elliptic (GHSA-848j) remains — no patched release on npm (<0.0.0). Made-with: Cursor
Made-with: Cursor
Made-with: Cursor
… permissions Made-with: Cursor
…l codegen sinks Made-with: Cursor
Made-with: Cursor
7db2b81 to
01ca65b
Compare
Goal
Clear and prevent GitHub security alerts on this repository: Dependabot (transitive npm advisories in
pnpm-lock.yaml) and Code scanning (CodeQL: unsafe string embedding in generated code, workflow TOCTOU, missing explicitpermissions).Security & supply chain
packages/vite-plugin:hardenJsonStringLiteralForEmbeddedScript(+ tests), applied across virtual codegen sinks (icons,_shared/generateCombinedProjects,single-project,mmd) so dynamicimport()and embedded JSON literals satisfy CodeQL bad code sanitization expectations.package.json:pnpm.overridesraising floors for vulnerable transitives (e.g.lodash/lodash-es,path-to-regexp,picomatch,brace-expansion,bn.js,yaml,smol-toml,ajv,pbkdf2,sha.js,qs,min-document,diff, …).pnpm-lock.yaml: updated to match overrides.GitHub Actions & Code scanning
codeql.yml: analysis forlikec4/likec4andsraphaz/likec4;workflow_dispatchfor manual runs on the fork.issue-comment.yaml: checkout PRhead.shafrom the API (immutable) +persist-credentials: false— mitigates Untrusted checkout TOCTOU.checks.yaml: workflow defaultcontents: read;actions: writeonly on jobs that upload or download artifacts (check-build,check-e2e-tests,check-e2e-types) — least privilege while keeping artifact steps working (CodeRabbit’s “drop actions: write” globally would break uploads).ci-pr.yaml/push.yaml/pkg-pr-new.yaml/trigger-deploy-template.yaml: explicit top-levelpermissionswhere required for callers or standalone workflows.Chores
.gitignore: local.gh-pr-*.mddrafts.Changesets
.changeset/security-icons-codeql-lockfile.md— patch bump forlikec4(security hardening).Verification
pnpm typecheck/pnpm test(local)