Skip to content
Open
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
5 changes: 5 additions & 0 deletions .github/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
changelog:
exclude:
authors:
- dependabot[bot]
- pre-commit-ci[bot]
15 changes: 1 addition & 14 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,21 +1,8 @@
repos:
- repo: https://github.com/codespell-project/codespell
rev: v2.4.0
rev: v2.4.1
hooks:
- id: codespell
args: [--ignore-words-list, "abandonned,ackward,bu"]
additional_dependencies:
- tomli
- repo: https://github.com/gitleaks/gitleaks
rev: v8.16.3
hooks:
- id: gitleaks
- repo: https://github.com/jumanjihouse/pre-commit-hooks
rev: 3.0.0
hooks:
- id: shellcheck
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
6 changes: 2 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
FROM python:3.14-alpine3.23@sha256:faee120f7885a06fcc9677922331391fa690d911c020abb9e8025ff3d908e510

RUN apk add --no-cache curl jq && apk upgrade --no-cache zlib
FROM python:3.13-alpine

COPY LICENSE \
README.md \
Expand All @@ -9,7 +7,7 @@ COPY LICENSE \
requirements.txt \
/code/

RUN pip install -r /code/requirements.txt
RUN pip install --no-cache-dir -r /code/requirements.txt

ENTRYPOINT ["/code/entrypoint.sh"]
CMD []
25 changes: 12 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
[![StepSecurity Maintained Action](https://raw.githubusercontent.com/step-security/maintained-actions-assets/main/assets/maintained-action-banner.png)](https://docs.stepsecurity.io/actions/stepsecurity-maintained-actions)

# Codespell with GitHub Actions -- including annotations for Pull Requests

This GitHub Actions runs codespell over your code.
Expand All @@ -8,7 +6,8 @@ Any warnings or errors will be annotated in the Pull Request.
## Usage

```yml
uses: step-security/actions-codespell@v2
- uses: actions/checkout@v5
- uses: codespell-project/actions-codespell@v2
```

### Parameter: check_filenames
Expand All @@ -18,7 +17,7 @@ If set, check file names for spelling mistakes as well.
This parameter is optional; by default `codespell` will only check the file contents.

```yml
uses: step-security/actions-codespell@v2
uses: codespell-project/actions-codespell@v2
with:
check_filenames: true
```
Expand All @@ -30,7 +29,7 @@ If set, check hidden files (those starting with ".") for spelling mistakes as we
This parameter is optional; by default `codespell` will not check hidden files.

```yml
uses: step-security/actions-codespell@v2
uses: codespell-project/actions-codespell@v2
with:
check_hidden: true
```
Expand All @@ -42,7 +41,7 @@ File with lines that should not be checked for spelling mistakes.
This parameter is optional; by default `codespell` will check all lines.

```yml
uses: step-security/actions-codespell@v2
uses: codespell-project/actions-codespell@v2
with:
exclude_file: src/foo
```
Expand All @@ -54,7 +53,7 @@ Comma-separated list of files to skip (it accepts globs as well).
This parameter is optional; by default `codespell` won't skip any files.

```yml
uses: step-security/actions-codespell@v2
uses: codespell-project/actions-codespell@v2
with:
skip: foo,bar
```
Expand All @@ -66,7 +65,7 @@ Comma-separated list of builtin dictionaries to use.
This parameter is optional; by default `codespell` will use its default selection of built in dictionaries.

```yml
uses: step-security/actions-codespell@v2
uses: codespell-project/actions-codespell@v2
with:
builtin: clear,rare
```
Expand All @@ -79,7 +78,7 @@ Words are case sensitive based on how they are written in the dictionary file.
This parameter is optional; by default `codespell` will check all words for typos.

```yml
uses: step-security/actions-codespell@v2
uses: codespell-project/actions-codespell@v2
with:
ignore_words_file: .codespellignore
```
Expand All @@ -92,7 +91,7 @@ Words are case sensitive based on how they are written in the dictionary file.
This parameter is optional; by default `codespell` will check all words for typos.

```yml
uses: step-security/actions-codespell@v2
uses: codespell-project/actions-codespell@v2
with:
ignore_words_list: abandonned,ackward
```
Expand All @@ -106,7 +105,7 @@ If set to "*", all misspelling in URIs and emails will be ignored.
This parameter is optional; by default `codespell` will check all URIs and emails for typos.

```yml
uses: step-security/actions-codespell@v2
uses: codespell-project/actions-codespell@v2
with:
uri_ignore_words_list: abandonned
```
Expand All @@ -119,7 +118,7 @@ This can be useful if your project has code you don't want to spell check for so
This parameter is optional; by default `codespell` will run on your whole repository.

```yml
uses: step-security/actions-codespell@v2
uses: codespell-project/actions-codespell@v2
with:
path: src
```
Expand All @@ -133,7 +132,7 @@ All errors and warnings are annotated in Pull Requests, but it will act like eve
This parameter is optional; setting this to any value will enable it.

```yml
uses: step-security/actions-codespell@v2
uses: codespell-project/actions-codespell@v2
with:
only_warn: 1
```
22 changes: 13 additions & 9 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
name: 'Codespell with annotations'
author: 'step-security'
author: 'Peter Newman'
description: 'Codespell with annotations for Pull Request'
inputs:
builtin:
description: 'Comma-separated list of builtin dictionaries to include'
required: false
default: ''
check_filenames:
description: 'If set, check file names as well'
required: false
Expand All @@ -10,16 +14,12 @@ inputs:
description: 'If set, check hidden files (those starting with ".") as well'
required: false
default: ''
exclude_file:
description: 'File with lines that should not be checked for spelling mistakes'
config:
description: 'Path to a codespell config file'
required: false
default: ''
skip:
description: 'Comma-separated list of files to skip (it accepts globs as well)'
required: false
default: './.git'
builtin:
description: 'Comma-separated list of builtin dictionaries to include'
exclude_file:
description: 'File with lines that should not be checked for spelling mistakes'
required: false
default: ''
ignore_words_file:
Expand All @@ -38,6 +38,10 @@ inputs:
description: 'Path to run codespell in'
required: false
default: ''
skip:
description: 'Comma-separated list of files to skip (it accepts globs as well)'
required: false
default: './.git'
only_warn:
description: 'If set, only warn, never error'
required: false
Expand Down
66 changes: 14 additions & 52 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,49 +1,7 @@
#!/bin/sh

REPO_PRIVATE=$(jq -r '.repository.private | tostring' "$GITHUB_EVENT_PATH" 2>/dev/null || echo "")
UPSTREAM="codespell-project/actions-codespell"
ACTION_REPO="${GITHUB_ACTION_REPOSITORY:-}"
DOCS_URL="https://docs.stepsecurity.io/actions/stepsecurity-maintained-actions"

echo ""
echo -e "\033[1;36mStepSecurity Maintained Action\033[0m"
echo "Secure drop-in replacement for $UPSTREAM"
if [ "$REPO_PRIVATE" = "false" ]; then
echo -e "\033[32m✓ Free for public repositories\033[0m"
fi
echo -e "\033[36mLearn more:\033[0m $DOCS_URL"
echo ""

if [ "$REPO_PRIVATE" != "false" ]; then
SERVER_URL="${GITHUB_SERVER_URL:-https://github.com}"

if [ "$SERVER_URL" != "https://github.com" ]; then
BODY=$(printf '{"action":"%s","ghes_server":"%s"}' "$ACTION_REPO" "$SERVER_URL")
else
BODY=$(printf '{"action":"%s"}' "$ACTION_REPO")
fi

API_URL="https://agent.api.stepsecurity.io/v1/github/$GITHUB_REPOSITORY/actions/maintained-actions-subscription"

RESPONSE=$(curl --max-time 3 -s -w "%{http_code}" \
-X POST \
-H "Content-Type: application/json" \
-d "$BODY" \
"$API_URL" -o /dev/null) && CURL_EXIT_CODE=0 || CURL_EXIT_CODE=$?

if [ $CURL_EXIT_CODE -ne 0 ]; then
echo "Timeout or API not reachable. Continuing to next step."
elif [ "$RESPONSE" = "403" ]; then
echo -e "::error::\033[1;31mThis action requires a StepSecurity subscription for private repositories.\033[0m"
echo -e "::error::\033[31mLearn how to enable a subscription: $DOCS_URL\033[0m"
exit 1
fi
fi

# Copy the matcher directly to RUNNER_TEMP; the /github/workflow bind-mount is not reliable.
CODE_DIR="${CODE_DIR:-/code}"
mkdir -p "${RUNNER_TEMP}/_github_workflow"
cp "${CODE_DIR}/codespell-matcher.json" "${RUNNER_TEMP}/_github_workflow/codespell-matcher.json"
# Copy the matcher to the host system; otherwise "add-matcher" can't find it.
cp /code/codespell-matcher.json /github/workflow/codespell-matcher.json
echo "::add-matcher::${RUNNER_TEMP}/_github_workflow/codespell-matcher.json"

# Run codespell.
Expand All @@ -52,6 +10,10 @@ echo "::add-matcher::${RUNNER_TEMP}/_github_workflow/codespell-matcher.json"
# e.g. PIPESTATUS and pipestatus only work in bash/zsh respectively.
echo "Running codespell on '${INPUT_PATH}' with the following options..."
command_args=""
echo "Builtin dictionaries '${INPUT_BUILTIN}'"
if [ "x${INPUT_BUILTIN}" != "x" ]; then
command_args="${command_args} --builtin ${INPUT_BUILTIN}"
fi
echo "Check filenames? '${INPUT_CHECK_FILENAMES}'"
if [ -n "${INPUT_CHECK_FILENAMES}" ]; then
echo "Checking filenames"
Expand All @@ -62,18 +24,14 @@ if [ -n "${INPUT_CHECK_HIDDEN}" ]; then
echo "Checking hidden"
command_args="${command_args} --check-hidden"
fi
echo "Config '${INPUT_CONFIG}'"
if [ "x${INPUT_CONFIG}" != "x" ]; then
command_args="${command_args} --config ${INPUT_CONFIG}"
fi
echo "Exclude file '${INPUT_EXCLUDE_FILE}'"
if [ "x${INPUT_EXCLUDE_FILE}" != "x" ]; then
command_args="${command_args} --exclude-file ${INPUT_EXCLUDE_FILE}"
fi
echo "Skipping '${INPUT_SKIP}'"
if [ "x${INPUT_SKIP}" != "x" ]; then
command_args="${command_args} --skip ${INPUT_SKIP}"
fi
echo "Builtin dictionaries '${INPUT_BUILTIN}'"
if [ "x${INPUT_BUILTIN}" != "x" ]; then
command_args="${command_args} --builtin ${INPUT_BUILTIN}"
fi
echo "Ignore words file '${INPUT_IGNORE_WORDS_FILE}'"
if [ "x${INPUT_IGNORE_WORDS_FILE}" != "x" ]; then
command_args="${command_args} --ignore-words ${INPUT_IGNORE_WORDS_FILE}"
Expand All @@ -86,6 +44,10 @@ echo "Ignore URI words list '${INPUT_URI_IGNORE_WORDS_LIST}'"
if [ "x${INPUT_URI_IGNORE_WORDS_LIST}" != "x" ]; then
command_args="${command_args} --uri-ignore-words-list ${INPUT_URI_IGNORE_WORDS_LIST}"
fi
echo "Skipping '${INPUT_SKIP}'"
if [ "x${INPUT_SKIP}" != "x" ]; then
command_args="${command_args} --skip ${INPUT_SKIP}"
fi
echo "Resulting CLI options ${command_args}"
exec 5>&1
res=`{ { codespell --count ${command_args} ${INPUT_PATH}; echo $? 1>&4; } 1>&5; } 4>&1`
Expand Down
59 changes: 48 additions & 11 deletions test/test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,17 @@ function setup() {
[ -d "/code/" ] || sudo mkdir -p /code/
[ -f "/code/codespell-matcher.json" ] || sudo cp codespell-problem-matcher/codespell-matcher.json /code/
#ls -alR /code/
# Create the _github_workflow dir that entrypoint.sh copies the matcher into
[ -d "${RUNNER_TEMP}/_github_workflow/" ] || sudo mkdir -p ${RUNNER_TEMP}/_github_workflow/ && sudo chmod 777 ${RUNNER_TEMP}/_github_workflow/
# Add a random place BATS tries to put it
[ -d "/github/workflow/" ] || sudo mkdir -p /github/workflow/ && sudo chmod 777 /github/workflow/
#ls -alR /github/workflow/

# Set GITHUB_EVENT_PATH to a fake public-repo event so REPO_PRIVATE=false,
# which skips the subscription check and keeps banner output deterministic.
local event_file="/tmp/test-event.json"
printf '{"repository":{"private":false}}' > "${event_file}"
export GITHUB_EVENT_PATH="${event_file}"

# Set default input values
export INPUT_CHECK_FILENAMES=""
export INPUT_CHECK_HIDDEN=""
export INPUT_EXCLUDE_FILE=""
export INPUT_SKIP=""
export INPUT_BUILTIN=""
export INPUT_CONFIG=""
export INPUT_IGNORE_WORDS_FILE=""
export INPUT_IGNORE_WORDS_LIST=""
export INPUT_URI_IGNORE_WORDS_LIST=""
Expand All @@ -62,9 +55,9 @@ function setup() {
[ $status -eq $expectedExitStatus ]

# Check output
[[ "${output}" == *"::add-matcher::${RUNNER_TEMP}/_github_workflow/codespell-matcher.json"* ]]
outputRegex="Running codespell on '${INPUT_PATH}'"
[[ "${output}" =~ $outputRegex ]]
[ "${lines[0]}" == "::add-matcher::${RUNNER_TEMP}/_github_workflow/codespell-matcher.json" ]
outputRegex="^Running codespell on '${INPUT_PATH}'"
[[ "${lines[1]}" =~ $outputRegex ]]
[ "${lines[-4 - $errorCount]}" == "$errorCount" ]
[ "${lines[-3]}" == "Codespell found one or more problems" ]
[ "${lines[-2]}" == "::remove-matcher owner=codespell-matcher-default::" ]
Expand Down Expand Up @@ -102,6 +95,50 @@ function setup() {
[ "${lines[-4 - $errorCount]}" == "$errorCount" ]
}

@test "Pass an ill-formed file to INPUT_CONFIG" {
# codespell's exit status is 78 for a configparser.Error exception
expectedExitStatus=78
INPUT_CONFIG="./test/testdata/.badcfg"
run "./entrypoint.sh"
[ $status -eq $expectedExitStatus ]
}

@test "Pass a non-existing file to INPUT_CONFIG" {
errorCount=$((ROOT_MISSPELLING_COUNT + SUBFOLDER_MISSPELLING_COUNT))
# codespell's exit status is 0, or 65 if there are errors found
if [ $errorCount -eq 0 ]; then expectedExitStatus=0; else expectedExitStatus=65; fi
INPUT_CONFIG="./foo"
run "./entrypoint.sh"
[ $status -eq $expectedExitStatus ]

# Check output
[ "${lines[0]}" == "::add-matcher::${RUNNER_TEMP}/_github_workflow/codespell-matcher.json" ]
outputRegex="^Running codespell on '${INPUT_PATH}'"
[[ "${lines[1]}" =~ $outputRegex ]]
[ "${lines[-4 - $errorCount]}" == "$errorCount" ]
[ "${lines[-3]}" == "Codespell found one or more problems" ]
[ "${lines[-2]}" == "::remove-matcher owner=codespell-matcher-default::" ]
[ "${lines[-1]}" == "::remove-matcher owner=codespell-matcher-specified::" ]
}

@test "Pass a valid file to INPUT_CONFIG" {
errorCount=$((ROOT_MISSPELLING_COUNT + SUBFOLDER_MISSPELLING_COUNT))
# codespell's exit status is 0, or 65 if there are errors found
if [ $errorCount -eq 0 ]; then expectedExitStatus=0; else expectedExitStatus=65; fi
INPUT_CONFIG="./test/testdata/.goodcfg"
run "./entrypoint.sh"
[ $status -eq $expectedExitStatus ]

# Check output
[ "${lines[0]}" == "::add-matcher::${RUNNER_TEMP}/_github_workflow/codespell-matcher.json" ]
outputRegex="^Running codespell on '${INPUT_PATH}'"
[[ "${lines[1]}" =~ $outputRegex ]]
[ "${lines[-4 - $errorCount]}" == "$errorCount" ]
[ "${lines[-3]}" == "Codespell found one or more problems" ]
[ "${lines[-2]}" == "::remove-matcher owner=codespell-matcher-default::" ]
[ "${lines[-1]}" == "::remove-matcher owner=codespell-matcher-specified::" ]
}

@test "Use an exclude file" {
errorCount=$((ROOT_MISSPELLING_COUNT + SUBFOLDER_MISSPELLING_COUNT - EXCLUDED_MISSPELLING_COUNT))
# codespell's exit status is 0, or 65 if there are errors found
Expand Down
1 change: 1 addition & 0 deletions test/testdata/.badcfg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foobar =
1 change: 1 addition & 0 deletions test/testdata/.goodcfg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[codespell]
Loading