diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..0b8f685 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,14 @@ +# .github/labeler.yml — path-based PR auto-labels (actions/labeler@v5 format). +documentation: + - changed-files: + - any-glob-to-any-file: ["**/*.md", "docs/**"] +ci: + - changed-files: + - any-glob-to-any-file: [".github/**"] +dependencies: + - changed-files: + - any-glob-to-any-file: + ["**/package.json", "**/pubspec.yaml", "**/go.mod", "**/*.lock", "**/*lock.yaml"] +tests: + - changed-files: + - any-glob-to-any-file: ["**/*.test.*", "**/*_test.*", "test/**", "**/__tests__/**"] diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..9165e91 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,23 @@ +name: Dependency Review + +# Flags vulnerable or disallowed-license dependencies introduced by a PR before +# they merge. Replaces Dependabot's alerting with a hard PR gate. +on: + pull_request: + branches: ["main"] + +permissions: + contents: read + +jobs: + dependency-review: + name: Dependency review + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + - uses: actions/dependency-review-action@v4 + with: + fail-on-severity: high + comment-summary-in-pr: on-failure diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000..4f9c08f --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,18 @@ +name: Labeler + +# Auto-labels PRs by the paths they touch (config in .github/labeler.yml). +on: + pull_request_target: + types: [opened, synchronize, reopened] + +permissions: + contents: read + pull-requests: write + +jobs: + label: + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v5 + with: + sync-labels: true diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 0000000..485d5b1 --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,32 @@ +name: Scorecard + +# OpenSSF Scorecard — supply-chain security posture. Runs on push to the default +# branch and weekly; uploads SARIF so findings show in the Security tab. +on: + push: + branches: ["main"] + schedule: + - cron: "27 3 * * 1" # Mondays 03:27 UTC + workflow_dispatch: {} + +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + security-events: write # upload SARIF to code scanning + id-token: write # publish results to the OpenSSF API + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + - uses: ossf/scorecard-action@v2.4.0 + with: + results_file: results.sarif + results_format: sarif + publish_results: true + - uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: results.sarif diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..6df593d --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,30 @@ +name: Stale + +# Marks inactive issues/PRs stale, then closes them after a grace period. +on: + schedule: + - cron: "0 4 * * *" # daily 04:00 UTC + workflow_dispatch: {} + +permissions: + issues: write + pull-requests: write + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v9 + with: + days-before-stale: 60 + days-before-close: 14 + stale-issue-label: stale + stale-pr-label: stale + exempt-issue-labels: pinned,security,blocked + exempt-pr-labels: pinned,security,blocked + stale-issue-message: > + This issue has been inactive for 60 days and is now marked stale. + Comment to keep it open; it will close in 14 days otherwise. + stale-pr-message: > + This PR has been inactive for 60 days and is now marked stale. + Push or comment to keep it open; it will close in 14 days otherwise. diff --git a/.github/workflows/version-check.yml b/.github/workflows/version-check.yml new file mode 100644 index 0000000..04c7b25 --- /dev/null +++ b/.github/workflows/version-check.yml @@ -0,0 +1,48 @@ +name: Version Check + +# Every PR must bump the root VERSION file (plain "x.y.z"). Release tags it on +# merge. Used by repos with no package manifest (Go, C++, Shell). +on: + pull_request: + branches: ["main"] + types: [opened, synchronize, reopened] + +permissions: + contents: read + +jobs: + version-bumped: + name: version bumped + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 # need the base branch to diff the version + persist-credentials: false + - name: Read versions + id: v + run: | + git fetch --no-tags --depth=1 origin "${{ github.base_ref }}" + pr=$(tr -d ' \r\n' < VERSION) + # If VERSION doesn't exist on the base yet (the PR that introduces it), + # treat the base as 0.0.0 so any real version passes the bump check. + base=$(git show "origin/${{ github.base_ref }}:VERSION" 2>/dev/null | tr -d ' \r\n' || true) + base=${base:-0.0.0} + echo "pr=$pr" >> "$GITHUB_OUTPUT" + echo "base=$base" >> "$GITHUB_OUTPUT" + - name: Compare + env: + PR: ${{ steps.v.outputs.pr }} + BASE: ${{ steps.v.outputs.base }} + run: | + echo "base=$BASE pr=$PR" + if [ "$PR" = "$BASE" ]; then + echo "::error::VERSION not bumped (still $BASE)." + exit 1 + fi + greater=$(printf '%s\n%s\n' "$BASE" "$PR" | sort -V | tail -n1) + if [ "$greater" != "$PR" ]; then + echo "::error::VERSION $PR is lower than base $BASE." + exit 1 + fi + echo "Version bumped $BASE -> $PR ✓" diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..3eefcb9 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.0.0