Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM python:3.14-alpine3.23@sha256:faee120f7885a06fcc9677922331391fa690d911c020abb9e8025ff3d908e510

RUN apk add --no-cache curl && apk upgrade --no-cache zlib
RUN apk add --no-cache curl jq && apk upgrade --no-cache zlib

COPY LICENSE \
README.md \
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[![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 Down
57 changes: 40 additions & 17 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,26 +1,49 @@
#!/bin/sh

# Validate subscription status
API_URL="https://agent.api.stepsecurity.io/v1/github/$GITHUB_REPOSITORY/actions/subscription"
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"

# Set a timeout for the curl command (3 seconds)
RESPONSE=$(curl --max-time 3 -s -w "%{http_code}" "$API_URL" -o /dev/null) || true
CURL_EXIT_CODE=${?}
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 ""

# Decide based on curl exit code and HTTP status
if [ $CURL_EXIT_CODE -ne 0 ]; then
echo "Timeout or API not reachable. Continuing to next step."
elif [ "$RESPONSE" = "200" ]; then
:
elif [ "$RESPONSE" = "403" ]; then
echo "Subscription is not valid. Reach out to support@stepsecurity.io"
exit 1
else
echo "Timeout or API not reachable. Continuing to next step."
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 to the host system; otherwise "add-matcher" can't find it.
cp /code/codespell-matcher.json /github/workflow/codespell-matcher.json
# 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"
echo "::add-matcher::${RUNNER_TEMP}/_github_workflow/codespell-matcher.json"

# Run codespell.
Expand Down
14 changes: 11 additions & 3 deletions test/test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,18 @@ 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=""
Expand All @@ -54,9 +62,9 @@ function setup() {
[ $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 ]]
[[ "${output}" == *"::add-matcher::${RUNNER_TEMP}/_github_workflow/codespell-matcher.json"* ]]
outputRegex="Running codespell on '${INPUT_PATH}'"
[[ "${output}" =~ $outputRegex ]]
[ "${lines[-4 - $errorCount]}" == "$errorCount" ]
[ "${lines[-3]}" == "Codespell found one or more problems" ]
[ "${lines[-2]}" == "::remove-matcher owner=codespell-matcher-default::" ]
Expand Down
Loading