From 12833094ca526cef126cecc5772c62ac122fff9d Mon Sep 17 00:00:00 2001 From: Nikhil Rajput Date: Mon, 29 Jun 2026 17:10:49 +0530 Subject: [PATCH] ci: add CI, release, security workflows and VERSION file Introduce a standardized GitHub Actions suite for this C++ project: - ci.yml: cmake configure + build (Release) + ctest if present - version-check.yml: enforce VERSION bump on every PR vs master - release.yml: tag v and create a GitHub Release on push - scorecard.yml: OpenSSF Scorecard supply-chain analysis - stale.yml: mark and close inactive issues/PRs - labeler.yml + .github/labeler.yml: path-based PR auto-labels Add a root VERSION file (1.0.0) as the version source for the version-check and release workflows, since this repo has no package manifest. Remove the existing codeql.yml. --- .github/labeler.yml | 14 ++++++++ .github/workflows/ci.yml | 31 ++++++++++++++++++ .github/workflows/codeql.yml | 51 ----------------------------- .github/workflows/labeler.yml | 18 ++++++++++ .github/workflows/release.yml | 39 ++++++++++++++++++++++ .github/workflows/scorecard.yml | 32 ++++++++++++++++++ .github/workflows/stale.yml | 30 +++++++++++++++++ .github/workflows/version-check.yml | 48 +++++++++++++++++++++++++++ VERSION | 1 + 9 files changed, 213 insertions(+), 51 deletions(-) create mode 100644 .github/labeler.yml create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/labeler.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/scorecard.yml create mode 100644 .github/workflows/stale.yml create mode 100644 .github/workflows/version-check.yml create mode 100644 VERSION 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/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..17fa49f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,31 @@ +name: CI + +on: + push: + branches: ["master"] + pull_request: + branches: ["master"] + +permissions: + contents: read + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + - name: Configure + run: cmake -B build -DCMAKE_BUILD_TYPE=Release + - name: Build + run: cmake --build build --config Release + - name: Test + run: | + if [ -f build/CTestTestfile.cmake ]; then ctest --test-dir build --output-on-failure; \ + else echo "no ctest targets — skipping"; fi diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 654a80e..0000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: C++ Code Analysis - -on: - push: - branches: - - master - pull_request: - branches: - - master - -jobs: - build-and-analyze: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install C++ tools - run: sudo apt-get update && sudo apt-get install -y clang clang-tidy cppcheck cmake - - - name: List directory contents - run: ls -R - - - name: Check for CMakeLists.txt - run: | - if [ ! -f ./CMakeLists.txt ]; then - echo "CMakeLists.txt not found in the root directory." - exit 1 - fi - - - name: Create build directory - run: mkdir build - - - name: Run CMake - run: cmake -S . -B build - - - name: Build project - run: cmake --build build - - - name: Run cppcheck - run: cppcheck --enable=all --inconclusive --xml --xml-version=2 . 2> cppcheck-result.xml - - - name: Run clang-tidy - run: find . -name '*.cpp' | xargs clang-tidy -p build - - - name: Upload cppcheck results - uses: actions/upload-artifact@v3 - with: - name: cppcheck-result - path: cppcheck-result.xml 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/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..b3e974c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,39 @@ +name: Release + +# On push to the default branch (a merged PR), tag v and create a +# GitHub Release with generated notes — unless the tag already exists. For repos +# with no package manifest (C++, Shell). For Go (siphon) the existing GoReleaser +# workflow is itself triggered by this tag and builds the binaries. +on: + push: + branches: ["master"] + workflow_dispatch: {} + +permissions: + contents: read + +jobs: + release: + name: Tag and release + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + persist-credentials: false + - name: Read version + id: v + run: echo "tag=v$(tr -d ' \r\n' < VERSION)" >> "$GITHUB_OUTPUT" + - name: Release if new + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ steps.v.outputs.tag }} + run: | + if gh release view "$TAG" >/dev/null 2>&1 \ + || git ls-remote --tags origin "refs/tags/$TAG" | grep -q .; then + echo "Tag $TAG already exists — skipping."; exit 0 + fi + gh release create "$TAG" --target "${{ github.sha }}" --title "$TAG" --generate-notes + echo "Released $TAG ✓" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 0000000..1f0088f --- /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: ["master"] + 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..de5d8a7 --- /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: ["master"] + 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