Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/check-curly-quotes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Check Curly Quotes

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
check-curly-quotes:
name: Check for curly quotes
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Check for curly quotes
run: |
chmod +x scripts/check_curly_quotes.sh
./scripts/check_curly_quotes.sh
Comment on lines +15 to +25

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI 3 months ago

In general, the fix is to add an explicit permissions block to the workflow (either at the top level so it applies to all jobs, or directly under the specific job) and restrict GITHUB_TOKEN to the least privileges required. This workflow only checks out the repository and runs a script, so contents: read is sufficient.

The best minimally invasive fix here is to add a job-level permissions block under check-curly-quotes: specifying contents: read. This keeps the change tightly scoped to the job that CodeQL flagged and avoids assumptions about other jobs (none are shown). Concretely, in .github/workflows/check-curly-quotes.yml, under jobs: check-curly-quotes: name: Check for curly quotes, insert a permissions: mapping with contents: read at the standard indentation level. No imports or other definitions are needed; this is pure workflow configuration.

Suggested changeset 1
.github/workflows/check-curly-quotes.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/check-curly-quotes.yml b/.github/workflows/check-curly-quotes.yml
--- a/.github/workflows/check-curly-quotes.yml
+++ b/.github/workflows/check-curly-quotes.yml
@@ -14,6 +14,8 @@
   check-curly-quotes:
     name: Check for curly quotes
     runs-on: ubuntu-latest
+    permissions:
+      contents: read
     timeout-minutes: 5
     steps:
       - name: Checkout code
EOF
@@ -14,6 +14,8 @@
check-curly-quotes:
name: Check for curly quotes
runs-on: ubuntu-latest
permissions:
contents: read
timeout-minutes: 5
steps:
- name: Checkout code
Copilot is powered by AI and may make mistakes. Always verify output.
10 changes: 10 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
repos:
- repo: local
hooks:
- id: check-curly-quotes
name: Check for curly quotes
entry: bash scripts/check_curly_quotes.sh
language: system
pass_filenames: false
types: [text]
description: "Detect curly/smart quotes that should be straight quotes"
12 changes: 11 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: all dev build format lint test install clean lint_md lint_md_fix broken-links build-references preview-references format-check
.PHONY: all dev build format lint test install clean lint_md lint_md_fix broken-links build-references preview-references format-check check-curly-quotes fix-curly-quotes

# Default target
all: help
Expand Down Expand Up @@ -91,6 +91,14 @@ preview-references: check-pnpm
@echo "Previewing references..."
cd reference && pnpm i && pnpm run preview

check-curly-quotes:
@echo "Checking for curly quotes..."
@./scripts/check_curly_quotes.sh

fix-curly-quotes:
@echo "Fixing curly quotes..."
@./scripts/fix_curly_quotes.sh

help:
@echo "Available commands:"
@echo " make dev - Start development mode with file watching and mint dev"
Expand All @@ -102,6 +110,8 @@ help:
@echo " make lint - Lint code"
@echo " make lint_md - Lint markdown files"
@echo " make lint_md_fix - Lint and fix markdown files"
@echo " make check-curly-quotes - Check for curly/smart quotes"
@echo " make fix-curly-quotes - Replace curly quotes with straight quotes"
@echo " make test - Run tests"
@echo " make install - Install dependencies"
@echo " make clean - Clean build artifacts"
Expand Down
70 changes: 70 additions & 0 deletions scripts/check_curly_quotes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/bin/bash
# Check for curly/smart quotes in source files
#
# Detects:
# " (U+201C) - Left double quotation mark
# " (U+201D) - Right double quotation mark
# ' (U+2018) - Left single quotation mark
# ' (U+2019) - Right single quotation mark

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color

# Default to src/ if no arguments provided
if [ $# -eq 0 ]; then
SEARCH_PATHS="src/"
else
SEARCH_PATHS="$@"
fi

# Pattern for curly quotes
CURLY_QUOTE_PATTERN='[""'']'

# Find files with curly quotes
# Exclude reference directories (auto-generated) and build artifacts
FOUND_FILES=$(grep -r -l -E "$CURLY_QUOTE_PATTERN" $SEARCH_PATHS \
--include="*.md" \
--include="*.mdx" \
--include="*.py" \
--include="*.js" \
--include="*.ts" \
--include="*.jsx" \
--include="*.tsx" \
--include="*.json" \
--include="*.yaml" \
--include="*.yml" \
--exclude-dir=reference \
--exclude-dir=build \
--exclude-dir=node_modules \
--exclude-dir=.git \
--exclude-dir=.venv \
--exclude-dir=__pycache__ \
2>/dev/null || true)

if [ -n "$FOUND_FILES" ]; then
echo -e "${RED}Error: Curly quotes found in the following files:${NC}"
echo ""

for file in $FOUND_FILES; do
echo -e "${RED}$file:${NC}"
# Show line numbers and content with curly quotes
grep -n -E "$CURLY_QUOTE_PATTERN" "$file" | head -10
echo ""
done

echo "Please replace curly quotes with straight quotes:"
echo ' " -> " (left double quote)'
echo ' " -> " (right double quote)'
echo " ' -> ' (left single quote)"
echo " ' -> ' (right single quote)"
echo ""
echo "Tip: You can use 'make fix-curly-quotes' to automatically fix these."
exit 1
else
echo -e "${GREEN}No curly quotes found.${NC}"
exit 0
fi
57 changes: 57 additions & 0 deletions scripts/fix_curly_quotes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/bin/bash
# Fix curly/smart quotes by replacing them with straight quotes
#
# Replaces:
# " (U+201C) → " - Left double quotation mark
# " (U+201D) → " - Right double quotation mark
# ' (U+2018) → ' - Left single quotation mark
# ' (U+2019) → ' - Right single quotation mark

set -e

# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color

# Default to src/ if no arguments provided
if [ $# -eq 0 ]; then
SEARCH_PATHS="src/"
else
SEARCH_PATHS="$@"
fi

# Find all relevant files
FILES=$(find $SEARCH_PATHS \
-type f \
\( -name "*.md" -o -name "*.mdx" -o -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.jsx" -o -name "*.tsx" -o -name "*.json" -o -name "*.yaml" -o -name "*.yml" \) \
-not -path "*/reference/*" \
-not -path "*/build/*" \
-not -path "*/node_modules/*" \
-not -path "*/.git/*" \
-not -path "*/.venv/*" \
-not -path "*/__pycache__/*" \
2>/dev/null || true)

FIXED_COUNT=0

for file in $FILES; do
if grep -q -E '[""'']' "$file" 2>/dev/null; then
echo -e "${YELLOW}Fixing: $file${NC}"
# Use sed to replace curly quotes with straight quotes
# macOS and Linux compatible
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' -e 's/[""]/"/g' -e "s/['']/'/g" "$file"
else
sed -i -e 's/[""]/"/g' -e "s/['']/'/g" "$file"
fi
FIXED_COUNT=$((FIXED_COUNT + 1))
fi
done

if [ $FIXED_COUNT -gt 0 ]; then
echo ""
echo -e "${GREEN}Fixed curly quotes in $FIXED_COUNT file(s).${NC}"
else
echo -e "${GREEN}No curly quotes found. Nothing to fix.${NC}"
fi