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
32 changes: 26 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,27 +50,47 @@ jobs:
# Run the action against this very PR. A composite action can pass every
# static check and still fail at runtime, so exercise it for real.
#
# The action installs the linter with `go install`, which needs the
# DivergentCodes/commitlint module to be fetchable. While that repo is
# private the module proxy returns 404 on a hosted runner, so this job is
# skipped rather than left failing for a reason unrelated to this code.
# Once commitlint is public, delete the `if:` and this job runs everywhere.
# The action authenticates its module fetch, so this no longer depends on
# commitlint being public. It does depend on the token being able to read
# that repo: the default github.token is scoped to THIS repository, so while
# commitlint is private a cross-repo token (COMMITLINT_READ_TOKEN) is
# required. Skip when it is absent rather than fail for a reason unrelated
# to the code under review — once commitlint is public, neither is needed.
self-test:
if: ${{ github.repository_owner == 'DivergentCodes' && vars.COMMITLINT_PUBLIC == 'true' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: check module is reachable
id: reach
env:
TOKEN: ${{ secrets.COMMITLINT_READ_TOKEN }}
run: |
if curl -fsS -o /dev/null "https://proxy.golang.org/github.com/!divergent!codes/commitlint/@v/list"; then
echo "reachable=true" >> "$GITHUB_OUTPUT"
echo "commitlint is public; running self-test with the default token"
elif [ -n "${TOKEN:-}" ]; then
echo "reachable=true" >> "$GITHUB_OUTPUT"
echo "commitlint is private; running self-test with COMMITLINT_READ_TOKEN"
else
echo "reachable=false" >> "$GITHUB_OUTPUT"
echo "::notice::self-test skipped: commitlint is private and COMMITLINT_READ_TOKEN is not set"
fi

- name: run this action (advisory)
if: steps.reach.outputs.reachable == 'true'
uses: ./
with:
# Never fail this repo's CI on a contributor's commit style; the point
# is to prove the action executes, not to gate on its verdict.
pr-title-mode: warn
commits-mode: warn
github-token: ${{ secrets.COMMITLINT_READ_TOKEN || github.token }}

- name: run with commits-mode off
if: steps.reach.outputs.reachable == 'true'
uses: ./
with:
pr-title-mode: warn
commits-mode: off
github-token: ${{ secrets.COMMITLINT_READ_TOKEN || github.token }}
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,27 @@ merge with rebase or merge commits instead, set `commits-mode: block`.
| `scopes` | any | comma-separated allowed scopes |
| `require-scope` | `false` | require a `(scope)` |
| `max-subject-length` | `72` | subject length limit |
| `github-token` | `github.token` | fetches the commitlint module while its repo is private; unused once public |

## Permissions

`permissions: contents: read` is sufficient — enough for `actions/checkout`
to fetch the commits. The action makes no API calls, needs no token, and never
writes anything. With `commits-mode: off` it reads only the event payload and
needs no permissions beyond the workflow default.
to fetch the commits. The action makes no API calls and never writes anything.
With `commits-mode: off` it reads only the event payload.

While the `commitlint` repository is private, `go install` needs credentials
to fetch the module. The action rewrites only `github.com/DivergentCodes/`
URLs to carry `github-token`, so the token is never offered to another host or
org, and sets `GOPRIVATE` so the public proxy and checksum database are
bypassed. Pass a token that can read that repo:

```yaml
- uses: DivergentCodes/commitlint-action@<full-sha>
with:
github-token: ${{ secrets.COMMITLINT_READ_TOKEN }}
```

Once `commitlint` is public this is unnecessary and the default applies.

## Runner requirements

Expand Down
30 changes: 29 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ inputs:
max-subject-length:
description: Maximum subject line length
default: "72"
github-token:
description: >
Token used to fetch the commitlint module while its repository is
private. Unused once commitlint is public.
default: ${{ github.token }}

runs:
using: composite
Expand All @@ -40,11 +45,34 @@ runs:
go-version: stable
cache: false

# `go install` fetches over HTTPS with no credentials, so while the
# commitlint repo is private git prompts for a username and dies with
# "terminal prompts disabled". Rewrite only DivergentCodes URLs to carry
# the token, so it is never offered to another host or org, and set
# GOPRIVATE so the public proxy and checksum database — which cannot see a
# private module — are bypassed rather than consulted and failed.
#
# This is a no-op once commitlint is public: the rewrite still matches, but
# a public fetch would have succeeded anyway.
- name: Install commitlint
shell: bash
env:
VERSION: ${{ inputs.version }}
run: go install "github.com/DivergentCodes/commitlint@${VERSION}"
GH_TOKEN: ${{ inputs.github-token }}
GOPRIVATE: github.com/DivergentCodes/*
run: |
set -euo pipefail
cleanup() {
git config --global --unset-all \
url."https://x-access-token:${GH_TOKEN}@github.com/DivergentCodes/".insteadOf || true
}
trap cleanup EXIT
# The token stays in the environment rather than argv, and Actions
# masks it in logs; the trap keeps it out of later steps' git config.
git config --global \
url."https://x-access-token:${GH_TOKEN}@github.com/DivergentCodes/".insteadOf \
"https://github.com/DivergentCodes/"
go install "github.com/DivergentCodes/commitlint@${VERSION}"

- name: Lint PR title
if: ${{ inputs.pr-title-mode != 'off' && github.event_name == 'pull_request' }}
Expand Down
Loading