mirror of
https://github.com/ivuorinen/gh-action-readme.git
synced 2026-03-18 21:02:19 +00:00
Compare commits
39 Commits
4aaa63f4d7
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49d6923a24 | ||
|
|
e80c8bb3bf | ||
|
|
64ee9e8dd6 | ||
|
|
db3496d802 | ||
|
|
c9b1654b96 | ||
| d266beab79 | |||
| 042b7a27a4 | |||
|
|
ddf674d4c9 | ||
|
|
968fc9f98b | ||
|
|
97ff99caea | ||
|
|
fbbe021fed | ||
| 9845a0d777 | |||
|
|
8e1f51d1d4 | ||
|
|
39ea382811 | ||
|
|
2d6b874a55 | ||
|
|
2c5a968b48 | ||
|
|
caf3ede64b | ||
|
|
4bceee2069 | ||
|
|
fac4e97a9a | ||
|
|
d973b9a130 | ||
|
|
16348431b0 | ||
|
|
4440354048 | ||
|
|
5d8383951e | ||
|
|
8562c248df | ||
|
|
e7ab7074b1 | ||
|
|
f3d1f5f459 | ||
|
|
81ced12ffe | ||
|
|
5aa33336e6 | ||
|
|
139cc504f5 | ||
|
|
3d9fb03a1a | ||
|
|
716a2e3d60 | ||
|
|
4b32e263d7 | ||
|
|
16c6969feb | ||
|
|
b2ad49249b | ||
|
|
e494934804 | ||
|
|
29625f8b6d | ||
|
|
e0f55d590b | ||
|
|
e7f9218ad8 | ||
|
|
e9dec027b9 |
16
.github/workflows/ci.yml
vendored
16
.github/workflows/ci.yml
vendored
@@ -5,21 +5,29 @@ on:
|
|||||||
branches: [main]
|
branches: [main]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||||
|
with:
|
||||||
|
go-version-file: "go.mod"
|
||||||
|
check-latest: true
|
||||||
- name: Run golangci-lint
|
- name: Run golangci-lint
|
||||||
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
|
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
|
||||||
with:
|
with:
|
||||||
version: v2.7.2
|
version: v2.11.3
|
||||||
- name: Setup Node.js for EditorConfig tools
|
- name: Setup Node.js for EditorConfig tools
|
||||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||||
with:
|
with:
|
||||||
node-version: "24"
|
node-version: "24"
|
||||||
- name: Install EditorConfig tools
|
- name: Install EditorConfig tools
|
||||||
@@ -62,7 +70,7 @@ jobs:
|
|||||||
echo "Verifying generated documentation files..."
|
echo "Verifying generated documentation files..."
|
||||||
ls -la docs/
|
ls -la docs/
|
||||||
- name: Upload Generated Documentation
|
- name: Upload Generated Documentation
|
||||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: generated-documentation
|
name: generated-documentation
|
||||||
|
|||||||
32
.github/workflows/codeql.yml
vendored
32
.github/workflows/codeql.yml
vendored
@@ -8,41 +8,27 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: ["main"]
|
branches: ["main"]
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "30 1 * * 0" # Run at 1:30 AM UTC every Sunday
|
- cron: "30 1 * * 0"
|
||||||
merge_group:
|
merge_group:
|
||||||
|
|
||||||
permissions:
|
permissions: {}
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
analyze:
|
analyze:
|
||||||
name: Analyze
|
name: Analyze
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
packages: read
|
||||||
security-events: write
|
security-events: write
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
language: ["go"]
|
language: ["actions", "go"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: CodeQL Analysis
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: ivuorinen/actions/codeql-analysis@1da3a0e79fcd7da6bed9ee1979f1449ba11f58f9 # v2026.03.14
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
language: ${{ matrix.language }}
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
queries: security-and-quality
|
queries: security-and-quality
|
||||||
|
|
||||||
- name: Autobuild
|
|
||||||
uses: github/codeql-action/autobuild@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
|
|
||||||
with:
|
|
||||||
category: "/language:${{matrix.language}}"
|
|
||||||
|
|||||||
9
.github/workflows/commitlint.yml
vendored
9
.github/workflows/commitlint.yml
vendored
@@ -9,13 +9,14 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
permissions:
|
permissions: {}
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
commitlint:
|
commitlint:
|
||||||
name: Validate Commit Messages
|
name: Validate Commit Messages
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
@@ -23,13 +24,13 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||||
with:
|
with:
|
||||||
node-version: "24"
|
node-version: "24"
|
||||||
|
|
||||||
- name: Install commitlint
|
- name: Install commitlint
|
||||||
run: |
|
run: |
|
||||||
npm install --save-dev @commitlint/cli@19.6.1 @commitlint/config-conventional@19.6.0
|
npm install --save-dev @commitlint/cli@20.4.3 @commitlint/config-conventional@20.4.3
|
||||||
|
|
||||||
- name: Validate current commit (for single commits)
|
- name: Validate current commit (for single commits)
|
||||||
if: github.event_name == 'push'
|
if: github.event_name == 'push'
|
||||||
|
|||||||
5
.github/workflows/pr-lint.yml
vendored
5
.github/workflows/pr-lint.yml
vendored
@@ -12,8 +12,7 @@ concurrency:
|
|||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
permissions:
|
permissions: {}
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Linter:
|
Linter:
|
||||||
@@ -31,4 +30,4 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Run PR Lint
|
- name: Run PR Lint
|
||||||
# https://github.com/ivuorinen/actions
|
# https://github.com/ivuorinen/actions
|
||||||
uses: ivuorinen/actions/pr-lint@f98ae7cd7d0feb1f9d6b01de0addbb11414cfc73 # v2026.01.21
|
uses: ivuorinen/actions/pr-lint@1da3a0e79fcd7da6bed9ee1979f1449ba11f58f9 # v2026.03.14
|
||||||
|
|||||||
17
.github/workflows/release.yml
vendored
17
.github/workflows/release.yml
vendored
@@ -6,8 +6,7 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- "v*.*.*"
|
- "v*.*.*"
|
||||||
|
|
||||||
permissions:
|
permissions: {}
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
@@ -23,35 +22,35 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||||
with:
|
with:
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
- name: Set up Node.js (for cosign)
|
- name: Set up Node.js (for cosign)
|
||||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||||
with:
|
with:
|
||||||
node-version: "24"
|
node-version: "24"
|
||||||
|
|
||||||
- name: Install cosign
|
- name: Install cosign
|
||||||
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
|
uses: sigstore/cosign-installer@ba7bc0a3fef59531c69a25acd34668d6d3fe6f22 # v4.1.0
|
||||||
with:
|
with:
|
||||||
cosign-release: "v2.4.0"
|
cosign-release: "v2.4.0"
|
||||||
|
|
||||||
- name: Install syft
|
- name: Install syft
|
||||||
uses: anchore/sbom-action/download-syft@deef08a0db64bfad603422135db61477b16cef56 # v0.22.1
|
uses: anchore/sbom-action/download-syft@57aae528053a48a3f6235f2d9461b05fbcb7366d # v0.23.1
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||||
|
|
||||||
- name: Log in to GitHub Container Registry
|
- name: Log in to GitHub Container Registry
|
||||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
|
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0
|
||||||
with:
|
with:
|
||||||
distribution: goreleaser
|
distribution: goreleaser
|
||||||
version: latest
|
version: latest
|
||||||
|
|||||||
20
.github/workflows/security.yml
vendored
20
.github/workflows/security.yml
vendored
@@ -12,6 +12,8 @@ on:
|
|||||||
- cron: "0 2 * * 0"
|
- cron: "0 2 * * 0"
|
||||||
merge_group:
|
merge_group:
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# Comprehensive security coverage:
|
# Comprehensive security coverage:
|
||||||
# - govulncheck: Go-specific vulnerability scanning
|
# - govulncheck: Go-specific vulnerability scanning
|
||||||
@@ -30,7 +32,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||||
with:
|
with:
|
||||||
go-version-file: "go.mod"
|
go-version-file: "go.mod"
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -45,7 +47,7 @@ jobs:
|
|||||||
name: Trivy Security Scan
|
name: Trivy Security Scan
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: write # needed for Dependency Submission API (SBOM)
|
||||||
security-events: write
|
security-events: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
@@ -54,7 +56,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Run Trivy vulnerability scanner in repo mode
|
- name: Run Trivy vulnerability scanner in repo mode
|
||||||
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
|
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0
|
||||||
with:
|
with:
|
||||||
scan-type: "fs"
|
scan-type: "fs"
|
||||||
scan-ref: "."
|
scan-ref: "."
|
||||||
@@ -63,13 +65,13 @@ jobs:
|
|||||||
severity: "CRITICAL,HIGH,MEDIUM"
|
severity: "CRITICAL,HIGH,MEDIUM"
|
||||||
|
|
||||||
- name: Upload Trivy scan results to GitHub Security tab
|
- name: Upload Trivy scan results to GitHub Security tab
|
||||||
uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
|
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
sarif_file: "trivy-results.sarif"
|
sarif_file: "trivy-results.sarif"
|
||||||
|
|
||||||
- name: Run Trivy in GitHub SBOM mode and submit results to Dependency Graph
|
- name: Run Trivy in GitHub SBOM mode and submit results to Dependency Graph
|
||||||
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
|
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0
|
||||||
with:
|
with:
|
||||||
scan-type: "fs"
|
scan-type: "fs"
|
||||||
format: "github"
|
format: "github"
|
||||||
@@ -108,7 +110,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||||
with:
|
with:
|
||||||
go-version-file: "go.mod"
|
go-version-file: "go.mod"
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -135,14 +137,14 @@ jobs:
|
|||||||
run: docker build --build-arg TARGETPLATFORM=${{ env.TARGETPLATFORM }} -t gh-action-readme:test .
|
run: docker build --build-arg TARGETPLATFORM=${{ env.TARGETPLATFORM }} -t gh-action-readme:test .
|
||||||
|
|
||||||
- name: Run Trivy vulnerability scanner on Docker image
|
- name: Run Trivy vulnerability scanner on Docker image
|
||||||
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
|
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0
|
||||||
with:
|
with:
|
||||||
image-ref: "gh-action-readme:test"
|
image-ref: "gh-action-readme:test"
|
||||||
format: "sarif"
|
format: "sarif"
|
||||||
output: "trivy-docker-results.sarif"
|
output: "trivy-docker-results.sarif"
|
||||||
|
|
||||||
- name: Upload Docker Trivy scan results
|
- name: Upload Docker Trivy scan results
|
||||||
uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
|
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
sarif_file: "trivy-docker-results.sarif"
|
sarif_file: "trivy-docker-results.sarif"
|
||||||
@@ -161,7 +163,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Dependency Review
|
- name: Dependency Review
|
||||||
uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2
|
uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
|
||||||
with:
|
with:
|
||||||
fail-on-severity: high
|
fail-on-severity: high
|
||||||
comment-summary-in-pr: always
|
comment-summary-in-pr: always
|
||||||
|
|||||||
7
.github/workflows/stale.yml
vendored
7
.github/workflows/stale.yml
vendored
@@ -8,10 +8,7 @@ on:
|
|||||||
workflow_call:
|
workflow_call:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions: {}
|
||||||
contents: read
|
|
||||||
packages: read
|
|
||||||
statuses: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stale:
|
stale:
|
||||||
@@ -23,4 +20,4 @@ jobs:
|
|||||||
issues: write
|
issues: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: ivuorinen/actions/stale@f98ae7cd7d0feb1f9d6b01de0addbb11414cfc73 # v2026.01.21
|
- uses: ivuorinen/actions/stale@1da3a0e79fcd7da6bed9ee1979f1449ba11f58f9 # v2026.03.14
|
||||||
|
|||||||
5
.github/workflows/sync-labels.yml
vendored
5
.github/workflows/sync-labels.yml
vendored
@@ -20,8 +20,7 @@ concurrency:
|
|||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
permissions:
|
permissions: {}
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
labels:
|
labels:
|
||||||
@@ -40,4 +39,4 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: ⤵️ Sync Latest Labels Definitions
|
- name: ⤵️ Sync Latest Labels Definitions
|
||||||
uses: ivuorinen/actions/sync-labels@f98ae7cd7d0feb1f9d6b01de0addbb11414cfc73 # v2026.01.21
|
uses: ivuorinen/actions/sync-labels@1da3a0e79fcd7da6bed9ee1979f1449ba11f58f9 # v2026.03.14
|
||||||
|
|||||||
13
.gitleaks.toml
Normal file
13
.gitleaks.toml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
title = "gh-action-readme gitleaks configuration"
|
||||||
|
|
||||||
|
[extend]
|
||||||
|
useDefault = true
|
||||||
|
|
||||||
|
# Allowlist for test files and fixtures that intentionally contain placeholder tokens.
|
||||||
|
# These are not real secrets and are used only for testing purposes.
|
||||||
|
[allowlist]
|
||||||
|
description = "Test fixture files containing placeholder tokens"
|
||||||
|
paths = [
|
||||||
|
'''^testutil/test_constants\.go$''',
|
||||||
|
'''^testdata/''',
|
||||||
|
]
|
||||||
@@ -23,3 +23,6 @@ internal/wizard/validator_test.go:github-pat:204
|
|||||||
integration_test.go:github-pat:304
|
integration_test.go:github-pat:304
|
||||||
internal/config_test.go:github-pat:133
|
internal/config_test.go:github-pat:133
|
||||||
internal/config_test.go:github-pat:162
|
internal/config_test.go:github-pat:162
|
||||||
|
testdata/yaml-fixtures/configs/global-config-default.yml:github-pat:4
|
||||||
|
testutil/test_constants.go:github-pat:363
|
||||||
|
testutil/test_constants.go:github-pat:455
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.25.5
|
1.26.1
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ version: "2"
|
|||||||
|
|
||||||
run:
|
run:
|
||||||
timeout: 5m
|
timeout: 5m
|
||||||
go: "1.24"
|
go: "1.26"
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
default: standard
|
default: standard
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ repos:
|
|||||||
|
|
||||||
# Markdown linting with markdownlint-cli2 (excluding legacy files)
|
# Markdown linting with markdownlint-cli2 (excluding legacy files)
|
||||||
- repo: https://github.com/DavidAnson/markdownlint-cli2
|
- repo: https://github.com/DavidAnson/markdownlint-cli2
|
||||||
rev: v0.20.0
|
rev: v0.21.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: markdownlint-cli2
|
- id: markdownlint-cli2
|
||||||
args: [--fix]
|
args: [--fix]
|
||||||
@@ -42,7 +42,7 @@ repos:
|
|||||||
|
|
||||||
# EditorConfig checking
|
# EditorConfig checking
|
||||||
- repo: https://github.com/editorconfig-checker/editorconfig-checker
|
- repo: https://github.com/editorconfig-checker/editorconfig-checker
|
||||||
rev: v3.6.0
|
rev: v3.6.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: editorconfig-checker
|
- id: editorconfig-checker
|
||||||
alias: ec
|
alias: ec
|
||||||
@@ -65,7 +65,7 @@ repos:
|
|||||||
|
|
||||||
# GitHub Actions linting
|
# GitHub Actions linting
|
||||||
- repo: https://github.com/rhysd/actionlint
|
- repo: https://github.com/rhysd/actionlint
|
||||||
rev: v1.7.10
|
rev: v1.7.11
|
||||||
hooks:
|
hooks:
|
||||||
- id: actionlint
|
- id: actionlint
|
||||||
args: ["-shellcheck="]
|
args: ["-shellcheck="]
|
||||||
|
|||||||
@@ -153,6 +153,11 @@ refactor: move inline YAML to fixtures for better test maintainability
|
|||||||
- Do NOT argue or explain why they might be useful
|
- Do NOT argue or explain why they might be useful
|
||||||
- Just comply immediately and recommit without bylines
|
- Just comply immediately and recommit without bylines
|
||||||
|
|
||||||
|
### 🚫 Commit Messages Over 100 Characters
|
||||||
|
|
||||||
|
Commitlint enforces `header-max-length: 100`. Keep commit message first lines under 100 characters.
|
||||||
|
The `commit-msg` hook catches this locally if installed via `make pre-commit-install`.
|
||||||
|
|
||||||
### ✅ Prevention Mechanisms
|
### ✅ Prevention Mechanisms
|
||||||
|
|
||||||
**Before writing ANY code:**
|
**Before writing ANY code:**
|
||||||
|
|||||||
1
Makefile
1
Makefile
@@ -139,6 +139,7 @@ pre-commit-install: ## Install pre-commit hooks
|
|||||||
@command -v pre-commit >/dev/null 2>&1 || \
|
@command -v pre-commit >/dev/null 2>&1 || \
|
||||||
{ echo "Please install pre-commit or run 'make devtools'"; exit 1; }
|
{ echo "Please install pre-commit or run 'make devtools'"; exit 1; }
|
||||||
pre-commit install
|
pre-commit install
|
||||||
|
pre-commit install --hook-type commit-msg
|
||||||
|
|
||||||
pre-commit-update: ## Update pre-commit hooks to latest versions
|
pre-commit-update: ## Update pre-commit hooks to latest versions
|
||||||
@echo "Updating pre-commit hooks..."
|
@echo "Updating pre-commit hooks..."
|
||||||
|
|||||||
14
go.mod
14
go.mod
@@ -1,8 +1,6 @@
|
|||||||
module github.com/ivuorinen/gh-action-readme
|
module github.com/ivuorinen/gh-action-readme
|
||||||
|
|
||||||
go 1.24.0
|
go 1.26.1
|
||||||
|
|
||||||
toolchain go1.25.6
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/adrg/xdg v0.5.3
|
github.com/adrg/xdg v0.5.3
|
||||||
@@ -14,12 +12,12 @@ require (
|
|||||||
github.com/schollz/progressbar/v3 v3.19.0
|
github.com/schollz/progressbar/v3 v3.19.0
|
||||||
github.com/spf13/cobra v1.10.2
|
github.com/spf13/cobra v1.10.2
|
||||||
github.com/spf13/viper v1.21.0
|
github.com/spf13/viper v1.21.0
|
||||||
golang.org/x/oauth2 v0.34.0
|
golang.org/x/oauth2 v0.36.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||||
github.com/google/go-querystring v1.2.0 // indirect
|
github.com/google/go-querystring v1.2.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
@@ -33,8 +31,8 @@ require (
|
|||||||
github.com/spf13/pflag v1.0.10 // indirect
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
golang.org/x/sys v0.39.0 // indirect
|
golang.org/x/sys v0.42.0 // indirect
|
||||||
golang.org/x/term v0.38.0 // indirect
|
golang.org/x/term v0.41.0 // indirect
|
||||||
golang.org/x/text v0.32.0 // indirect
|
golang.org/x/text v0.35.0 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
20
go.sum
20
go.sum
@@ -83,8 +83,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
|
|||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||||
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
@@ -410,8 +410,8 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ
|
|||||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||||
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -473,14 +473,14 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||||
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
|
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
|
||||||
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
|
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -491,8 +491,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
|||||||
@@ -39,19 +39,19 @@ func (ce *ContextualError) Error() string {
|
|||||||
|
|
||||||
// Primary error message
|
// Primary error message
|
||||||
if ce.Context != "" {
|
if ce.Context != "" {
|
||||||
b.WriteString(fmt.Sprintf("%s: %v", ce.Context, ce.Err))
|
fmt.Fprintf(&b, "%s: %v", ce.Context, ce.Err)
|
||||||
} else {
|
} else {
|
||||||
b.WriteString(ce.Err.Error())
|
b.WriteString(ce.Err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add error code for reference
|
// Add error code for reference
|
||||||
b.WriteString(fmt.Sprintf(" [%s]", ce.Code))
|
fmt.Fprintf(&b, " [%s]", ce.Code)
|
||||||
|
|
||||||
// Add details if available
|
// Add details if available
|
||||||
if len(ce.Details) > 0 {
|
if len(ce.Details) > 0 {
|
||||||
b.WriteString("\n\nDetails:")
|
b.WriteString("\n\nDetails:")
|
||||||
for key, value := range ce.Details {
|
for key, value := range ce.Details {
|
||||||
b.WriteString(fmt.Sprintf("\n %s: %s", key, value))
|
fmt.Fprintf(&b, "\n %s: %s", key, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -936,7 +936,7 @@ func TestNewGitHubClientEdgeCases(t *testing.T) {
|
|||||||
expectError: false,
|
expectError: false,
|
||||||
description: "Should create client with valid classic token",
|
description: "Should create client with valid classic token",
|
||||||
},
|
},
|
||||||
{
|
{ // #nosec G101 -- test token, not a real credential
|
||||||
name: "valid fine-grained PAT",
|
name: "valid fine-grained PAT",
|
||||||
token: "github_pat_11AAAAAA0AAAAaAaaAaaaAaa_AaAAaAAaAAAaAAAAAaAAaAAaAaAAaAAAAaAAAAAAAAaAAaAAaAaaAA",
|
token: "github_pat_11AAAAAA0AAAAaAaaAaaaAaa_AaAAaAAaAAAaAAAAAaAAaAAaAaAAaAAAAaAAAAAAAAaAAaAAaAaaAA",
|
||||||
expectError: false,
|
expectError: false,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -591,15 +592,26 @@ func (a *Analyzer) determineUpdateType(currentParts, latestParts []string) strin
|
|||||||
|
|
||||||
// updateActionFile applies updates to a single action file.
|
// updateActionFile applies updates to a single action file.
|
||||||
func (a *Analyzer) updateActionFile(filePath string, updates []PinnedUpdate) error {
|
func (a *Analyzer) updateActionFile(filePath string, updates []PinnedUpdate) error {
|
||||||
|
// filepath.Clean normalises the path (removes redundant separators, ".", "..").
|
||||||
|
// It does NOT validate containment within a root directory; the actual security
|
||||||
|
// justification for the #nosec annotations below is that filePath originates
|
||||||
|
// from the tool's own filesystem discovery (DiscoverActionFilesWithValidation),
|
||||||
|
// not from direct, uncontrolled user input.
|
||||||
|
cleanPath := filepath.Clean(filePath)
|
||||||
|
|
||||||
// Read the file
|
// Read the file
|
||||||
content, err := os.ReadFile(filePath) // #nosec G304 -- file path from function parameter
|
content, err := os.ReadFile(cleanPath) // #nosec G304 -- path from tool-internal filesystem scan
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read file: %w", err)
|
return fmt.Errorf("failed to read file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create backup
|
// Create backup
|
||||||
backupPath := filePath + appconstants.BackupExtension
|
backupPath := cleanPath + appconstants.BackupExtension
|
||||||
if err := os.WriteFile(backupPath, content, appconstants.FilePermDefault); err != nil { // #nosec G306
|
if err := os.WriteFile( // #nosec G306 G703 -- path from tool-internal filesystem scan
|
||||||
|
backupPath,
|
||||||
|
content,
|
||||||
|
appconstants.FilePermDefault,
|
||||||
|
); err != nil {
|
||||||
return fmt.Errorf("failed to create backup: %w", err)
|
return fmt.Errorf("failed to create backup: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,12 +621,16 @@ func (a *Analyzer) updateActionFile(filePath string, updates []PinnedUpdate) err
|
|||||||
|
|
||||||
// Write updated content
|
// Write updated content
|
||||||
updatedContent := strings.Join(lines, "\n")
|
updatedContent := strings.Join(lines, "\n")
|
||||||
if err := os.WriteFile(filePath, []byte(updatedContent), appconstants.FilePermDefault); err != nil { // #nosec G306
|
if err := os.WriteFile( // #nosec G306 G703 -- path from tool-internal filesystem scan
|
||||||
|
cleanPath,
|
||||||
|
[]byte(updatedContent),
|
||||||
|
appconstants.FilePermDefault,
|
||||||
|
); err != nil {
|
||||||
return fmt.Errorf("failed to write updated file: %w", err)
|
return fmt.Errorf("failed to write updated file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate and rollback on failure
|
// Validate and rollback on failure
|
||||||
if err := a.validateAndRollbackOnFailure(filePath, backupPath); err != nil {
|
if err := a.validateAndRollbackOnFailure(cleanPath, backupPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -601,7 +601,7 @@ func (g *Generator) countValidationStats(results []ValidationResult) (validFiles
|
|||||||
// showValidationSummary displays the summary statistics.
|
// showValidationSummary displays the summary statistics.
|
||||||
func (g *Generator) showValidationSummary(totalFiles, validFiles, totalIssues, resultCount, errorCount int) {
|
func (g *Generator) showValidationSummary(totalFiles, validFiles, totalIssues, resultCount, errorCount int) {
|
||||||
g.Output.Bold("\nValidation Summary for %d files:", totalFiles)
|
g.Output.Bold("\nValidation Summary for %d files:", totalFiles)
|
||||||
g.Output.Printf("=" + strings.Repeat("=", 35) + "\n")
|
g.Output.Printf("%s", "="+strings.Repeat("=", 35)+"\n")
|
||||||
|
|
||||||
g.Output.Success("Valid files: %d", validFiles)
|
g.Output.Success("Valid files: %d", validFiles)
|
||||||
if resultCount-validFiles > 0 {
|
if resultCount-validFiles > 0 {
|
||||||
@@ -622,7 +622,7 @@ func (g *Generator) showDetailedIssues(results []ValidationResult, totalIssues i
|
|||||||
}
|
}
|
||||||
|
|
||||||
g.Output.Bold("\nDetailed Issues & Suggestions:")
|
g.Output.Bold("\nDetailed Issues & Suggestions:")
|
||||||
g.Output.Printf("-" + strings.Repeat("-", 35) + "\n")
|
g.Output.Printf("%s", "-"+strings.Repeat("-", 35)+"\n")
|
||||||
|
|
||||||
for _, result := range results {
|
for _, result := range results {
|
||||||
if len(result.MissingFields) > 1 || len(result.Warnings) > 0 {
|
if len(result.MissingFields) > 1 || len(result.Warnings) > 0 {
|
||||||
@@ -663,7 +663,7 @@ func (g *Generator) showParseErrors(errors []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
g.Output.Bold("\nParse Errors:")
|
g.Output.Bold("\nParse Errors:")
|
||||||
g.Output.Printf("-" + strings.Repeat("-", 15) + "\n")
|
g.Output.Printf("%s", "-"+strings.Repeat("-", 15)+"\n")
|
||||||
for _, errMsg := range errors {
|
for _, errMsg := range errors {
|
||||||
g.Output.Error(" - %s", errMsg)
|
g.Output.Error(" - %s", errMsg)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -644,7 +644,7 @@ func TestConfigureGitHubIntegration(t *testing.T) {
|
|||||||
wantTokenSet: false,
|
wantTokenSet: false,
|
||||||
wantTokenValue: "",
|
wantTokenValue: "",
|
||||||
},
|
},
|
||||||
{
|
{ // #nosec G101 -- test token, not a real credential
|
||||||
name: "existing token skips setup",
|
name: "existing token skips setup",
|
||||||
inputs: "",
|
inputs: "",
|
||||||
existingToken: "ghp_existing_token",
|
existingToken: "ghp_existing_token",
|
||||||
|
|||||||
@@ -1005,7 +1005,7 @@ func TestValidateGitHubToken(t *testing.T) {
|
|||||||
token string
|
token string
|
||||||
want bool
|
want bool
|
||||||
}{
|
}{
|
||||||
{
|
{ // #nosec G101 -- test token, not a real credential
|
||||||
name: "with valid token",
|
name: "with valid token",
|
||||||
token: "ghp_test_token_123",
|
token: "ghp_test_token_123",
|
||||||
want: true,
|
want: true,
|
||||||
|
|||||||
4
testdata/composite-action/action.yml
vendored
4
testdata/composite-action/action.yml
vendored
@@ -18,13 +18,13 @@ runs:
|
|||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
token: ${{ github.token }}
|
token: ${{ github.token }}
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ inputs.node-version }}
|
node-version: ${{ inputs.node-version }}
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ func WriteTestFile(t *testing.T, path, content string) {
|
|||||||
t.Fatalf("failed to create dir %s: %v", dir, err)
|
t.Fatalf("failed to create dir %s: %v", dir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// #nosec G306 -- test file permissions
|
// #nosec G306 G703 -- test file permissions, path is controlled by test infrastructure
|
||||||
if err := os.WriteFile(path, []byte(content), appconstants.FilePermDefault); err != nil {
|
if err := os.WriteFile(path, []byte(content), appconstants.FilePermDefault); err != nil {
|
||||||
t.Fatalf("failed to write test file %s: %v", path, err)
|
t.Fatalf("failed to write test file %s: %v", path, err)
|
||||||
}
|
}
|
||||||
@@ -396,7 +396,7 @@ func AssertFileNotExists(t *testing.T, path string) {
|
|||||||
func CreateTestAction(name, description string, inputs map[string]string) string {
|
func CreateTestAction(name, description string, inputs map[string]string) string {
|
||||||
var inputsYAML bytes.Buffer
|
var inputsYAML bytes.Buffer
|
||||||
for key, desc := range inputs {
|
for key, desc := range inputs {
|
||||||
inputsYAML.WriteString(fmt.Sprintf(" %s:\n description: %s\n required: true\n", key, desc))
|
fmt.Fprintf(&inputsYAML, " %s:\n description: %s\n required: true\n", key, desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
result := fmt.Sprintf(appconstants.YAMLFieldName, name)
|
result := fmt.Sprintf(appconstants.YAMLFieldName, name)
|
||||||
@@ -445,7 +445,7 @@ func SetupTestTemplates(t *testing.T, dir string) {
|
|||||||
func CreateCompositeAction(name, description string, steps []string) string {
|
func CreateCompositeAction(name, description string, steps []string) string {
|
||||||
var stepsYAML bytes.Buffer
|
var stepsYAML bytes.Buffer
|
||||||
for i, step := range steps {
|
for i, step := range steps {
|
||||||
stepsYAML.WriteString(fmt.Sprintf(" - name: Step %d\n uses: %s\n", i+1, step))
|
fmt.Fprintf(&stepsYAML, " - name: Step %d\n uses: %s\n", i+1, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
result := fmt.Sprintf(appconstants.YAMLFieldName, name)
|
result := fmt.Sprintf(appconstants.YAMLFieldName, name)
|
||||||
@@ -521,11 +521,9 @@ func SetEnv(t *testing.T, key, value string) func() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WithContext creates a context with timeout for testing.
|
// WithContext creates a context with timeout for testing.
|
||||||
func WithContext(timeout time.Duration) context.Context {
|
// The caller is responsible for calling the returned cancel function.
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
func WithContext(timeout time.Duration) (context.Context, context.CancelFunc) {
|
||||||
_ = cancel // Avoid lostcancel - we're intentionally creating a context without cleanup for testing
|
return context.WithTimeout(context.Background(), timeout)
|
||||||
|
|
||||||
return ctx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssertNoError fails the test if err is not nil.
|
// AssertNoError fails the test if err is not nil.
|
||||||
|
|||||||
@@ -697,7 +697,8 @@ func TestWithContext(t *testing.T) {
|
|||||||
t.Run("creates context with timeout", func(t *testing.T) {
|
t.Run("creates context with timeout", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
timeout := 100 * time.Millisecond
|
timeout := 100 * time.Millisecond
|
||||||
ctx := WithContext(timeout)
|
ctx, cancel := WithContext(timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
t.Fatal("expected context to be created")
|
t.Fatal("expected context to be created")
|
||||||
@@ -719,7 +720,8 @@ func TestWithContext(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("context eventually times out", func(t *testing.T) {
|
t.Run("context eventually times out", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
ctx := WithContext(1 * time.Millisecond)
|
ctx, cancel := WithContext(1 * time.Millisecond)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
// Wait a bit longer than the timeout
|
// Wait a bit longer than the timeout
|
||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
|||||||
Reference in New Issue
Block a user