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
4 changes: 4 additions & 0 deletions .github/labels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
color: "ededed"
description: Dependency updates (usually opened by Dependabot)

- name: github-actions
color: "2088FF"
description: Updates to GitHub Actions dependencies (Dependabot ecosystem)

- name: github-config
color: "f9d0c4"
description: Changes to repository configuration (templates, CODEOWNERS, labeler, etc.)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/go-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ jobs:
run: ${{ inputs.test_cmd }}

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@e24998b8b67b290c2fa8b7c14fcfa7de2c5c9b8c # v7
uses: goreleaser/goreleaser-action@1a80836c5c9d9e5755a25cb59ec6f45a3b5f41a8 # v7
with:
distribution: ${{ inputs.goreleaser_distribution }}
version: ${{ inputs.goreleaser_version }}
Expand Down
46 changes: 23 additions & 23 deletions .github/workflows/go-security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Dependency Review
uses: actions/dependency-review-action@v4
uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
with:
fail-on-severity: moderate

Expand All @@ -90,22 +90,22 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Set up Go
uses: actions/setup-go@v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: ${{ inputs.go_version }}
cache: true

- name: Run Gosec Security Scanner
uses: securego/gosec@master
uses: securego/gosec@223e19b8856e00f02cc67804499a83f77e208f3c # v2.25.0
with:
args: '-no-fail -fmt sarif -out gosec-results.sarif ./...'

- name: Upload Gosec SARIF
if: always() && inputs.upload_sarif
uses: github/codeql-action/upload-sarif@v4
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
Comment thread
bedatty marked this conversation as resolved.
with:
sarif_file: gosec-results.sarif
category: gosec
Expand All @@ -117,10 +117,10 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Set up Go
uses: actions/setup-go@v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: ${{ inputs.go_version }}
cache: true
Expand All @@ -138,10 +138,10 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Set up Go
uses: actions/setup-go@v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: ${{ inputs.go_version }}
cache: true
Expand All @@ -150,7 +150,7 @@ jobs:
run: go list -json -m all > go.list

- name: Nancy vulnerability scan
uses: sonatype-nexus-community/nancy-github-action@main
uses: sonatype-nexus-community/nancy-github-action@726e338312e68ecdd4b4195765f174d3b3ce1533 # v1.0.3
with:
nancyCommand: sleuth --loud
continue-on-error: true
Expand All @@ -162,10 +162,10 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@0.35.0
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: 'fs'
scan-ref: '.'
Expand All @@ -175,7 +175,7 @@ jobs:

- name: Upload Trivy SARIF
if: always() && inputs.upload_sarif
uses: github/codeql-action/upload-sarif@v4
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
sarif_file: trivy-results.sarif
category: trivy
Expand All @@ -187,12 +187,12 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0

- name: TruffleHog OSS
uses: trufflesecurity/trufflehog@main
uses: trufflesecurity/trufflehog@17456f8c7d042d8c82c9a8ca9e937231f9f42e26 # v3.95.2
with:
path: ./
base: ${{ github.event.repository.default_branch }}
Expand All @@ -206,10 +206,10 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Set up Go
uses: actions/setup-go@v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: ${{ inputs.go_version }}
cache: true
Expand All @@ -227,7 +227,7 @@ jobs:
cat licenses.txt

- name: Upload license report
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: license-report
path: licenses.txt
Expand All @@ -240,22 +240,22 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Set up Go
uses: actions/setup-go@v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: ${{ inputs.go_version }}
cache: true

- name: Generate SBOM
uses: anchore/sbom-action@v0
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
with:
format: spdx-json
output-file: sbom.spdx.json

- name: Upload SBOM
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: sbom
path: sbom.spdx.json
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/self-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ on:
# The deployment matrix is resolved from main at runtime by callers, so
# matrix-only changes propagate without a new release tag.
- 'config/deployment-matrix.yml'
- '.github/workflows/self-*.yml'
tags-ignore:
- '**'

Expand Down
22 changes: 12 additions & 10 deletions .github/workflows/self-routine.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ name: Self — Repository Routines

on:
schedule:
- cron: "0 3 * * 1" # weekly Mon 03:00 UTC — branch cleanup (stale scan)
- cron: "0 4 * * *" # daily 04:00 UTC — stale PRs
- cron: "30 4 * * 3" # weekly Wed 04:30 UTC — stale issues
- cron: "0 5 * * 0" # weekly Sun 05:00 UTC — labels sync (reconciliation)
- cron: "0 6 1 * *" # monthly 1st 06:00 UTC — workflow runs cleanup
# Single weekly cron — every Monday at 03:00 UTC fires every routine in
# the same workflow run. Stale/cleanup actions are idempotent: any item
# that doesn't meet the threshold is logged and skipped, so running them
# together once a week is the simplest mental model with no real cost
# over staggered cadences.
- cron: "0 3 * * 1"
pull_request:
types: [closed]
push:
Expand Down Expand Up @@ -52,7 +53,7 @@ jobs:
branch_cleanup_stale:
name: Clean stale branches
if: |
(github.event_name == 'schedule' && github.event.schedule == '0 3 * * 1')
github.event_name == 'schedule'
|| (github.event_name == 'workflow_dispatch' && (inputs.routine == 'all' || inputs.routine == 'branch-cleanup-stale'))
uses: ./.github/workflows/branch-cleanup.yml
with:
Expand All @@ -65,10 +66,11 @@ jobs:
stale_pr:
name: Close stale PRs
if: |
(github.event_name == 'schedule' && github.event.schedule == '0 4 * * *')
github.event_name == 'schedule'
|| (github.event_name == 'workflow_dispatch' && (inputs.routine == 'all' || inputs.routine == 'stale-pr'))
uses: ./.github/workflows/stale-pr.yml
with:
operations_per_run: ${{ github.event_name == 'schedule' && 420 || 60 }}
dry_run: ${{ inputs.dry_run || false }}
secrets: inherit

Expand All @@ -77,7 +79,7 @@ jobs:
stale_issue:
name: Close stale issues
if: |
(github.event_name == 'schedule' && github.event.schedule == '30 4 * * 3')
github.event_name == 'schedule'
|| (github.event_name == 'workflow_dispatch' && (inputs.routine == 'all' || inputs.routine == 'stale-issue'))
uses: ./.github/workflows/stale-issue.yml
with:
Expand All @@ -92,7 +94,7 @@ jobs:
name: Sync labels
if: |
github.event_name == 'push'
|| (github.event_name == 'schedule' && github.event.schedule == '0 5 * * 0')
|| github.event_name == 'schedule'
|| (github.event_name == 'workflow_dispatch' && (inputs.routine == 'all' || inputs.routine == 'labels-sync'))
uses: ./.github/workflows/labels-sync.yml
with:
Expand All @@ -104,7 +106,7 @@ jobs:
workflow_runs_cleanup:
name: Delete old workflow runs
if: |
(github.event_name == 'schedule' && github.event.schedule == '0 6 1 * *')
github.event_name == 'schedule'
|| (github.event_name == 'workflow_dispatch' && (inputs.routine == 'all' || inputs.routine == 'workflow-runs-cleanup'))
uses: ./.github/workflows/workflow-runs-cleanup.yml
with:
Expand Down
54 changes: 43 additions & 11 deletions src/config/stale/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,19 +100,13 @@ runs:
echo "::notice title=Dry run::No labels or comments will be applied (debug-only mode)"
fi

cat <<'NOTE'

Reading the per-item log below:
• actions/stale uses the unified /issues API, so every item is
announced as "Issue #N" — even pull requests.
• Internally the tool checks isPullRequest and routes each item
to the matching rule set (days-before-pr-* vs days-before-issue-*).
• Items of a type whose days-before-*-stale is -1 are listed but
never marked, commented on, or closed.

NOTE
# Open a collapsible group around the verbose actions/stale per-item
# output that follows. The group is closed in the post-run summary
# step. Readers see the noisy log collapsed by default in the UI.
echo "::group::actions/stale per-item log (verbose; expand to inspect)"

- name: Flag and close stale PRs and issues
id: stale
uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
with:
repo-token: ${{ inputs.github-token }}
Expand All @@ -139,3 +133,41 @@ runs:
Closing this PR due to prolonged inactivity. Reopen if work resumes.
close-issue-message: >-
Closing this issue due to prolonged inactivity. Reopen if it is still relevant.

# ----------------- Post-run Summary -----------------
# Closes the collapsible group opened in the pre-flight step and emits
# a clean, deduplicated summary derived from the action's outputs so
# readers don't have to scan the verbose log to know what happened.
- name: Summarize stale scan outcome
if: always()
shell: bash
env:
STALE_OUTCOME: ${{ steps.stale.outcome }}
STALED: ${{ steps.stale.outputs.staled-issues-prs }}
CLOSED: ${{ steps.stale.outputs.closed-issues-prs }}
run: |
echo "::endgroup::"
echo ""

# When actions/stale didn't succeed, its outputs are empty for the
# wrong reason — reporting 0 marked / 0 closed would lie about the
# state of the run. Surface the real outcome instead.
if [ "$STALE_OUTCOME" != "success" ]; then
echo "::warning title=Stale scan summary unavailable::actions/stale outcome=${STALE_OUTCOME}; counts are not reliable."
exit 0
fi

count_csv() {
local csv="$1"
[ -z "$csv" ] && { echo 0; return; }
# Items are comma-separated; awk avoids subshell + tr cost.
awk -v s="$csv" 'BEGIN { n = split(s, a, ","); print n }'
}

staled_count=$(count_csv "$STALED")
closed_count=$(count_csv "$CLOSED")

echo "::notice title=Stale scan summary::Marked stale: ${staled_count} | Closed: ${closed_count}"
[ -n "$STALED" ] && echo " Marked stale: ${STALED}"
[ -n "$CLOSED" ] && echo " Closed: ${CLOSED}"
echo ""
Loading