diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 9889db3..804f515 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -17,7 +17,7 @@ jobs: # dorny/paths-filter comparison, and that comparison has no base outside a pull request. A # manual run is one somebody asked for regardless of what changed, so it skips the filter # instead of depending on what the filter would answer without a base. - uses: OneLiteFeatherNET/workflows/.github/workflows/gradle-build-pr.yml@v2.4.0 + uses: OneLiteFeatherNET/workflows/.github/workflows/gradle-build-pr.yml@v2.8.1 with: java-version: "25" java-distribution: "temurin" diff --git a/.github/workflows/close_invalid_prs.yml b/.github/workflows/close_invalid_prs.yml index 849d542..bd99444 100644 --- a/.github/workflows/close_invalid_prs.yml +++ b/.github/workflows/close_invalid_prs.yml @@ -6,5 +6,5 @@ on: jobs: close: - uses: OneLiteFeatherNET/workflows/.github/workflows/close-invalid-prs.yml@v2.4.0 + uses: OneLiteFeatherNET/workflows/.github/workflows/close-invalid-prs.yml@v2.8.1 secrets: inherit diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml new file mode 100644 index 0000000..759b37b --- /dev/null +++ b/.github/workflows/pr-lint.yml @@ -0,0 +1,17 @@ +name: PR Lint + +# Conventional Commits on the PR title and every commit on the branch. +# release-please parses those commit types to decide the version bump and to +# build the changelog - a non-conventional commit silently produces neither. +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +permissions: + contents: read + pull-requests: read + +jobs: + lint: + uses: OneLiteFeatherNET/workflows/.github/workflows/pr-lint.yml@v2.8.1 + secrets: inherit diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index a558ab2..354dc51 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -31,7 +31,7 @@ jobs: name: Publish to OneLiteFeatherRepo needs: release-please if: needs.release-please.outputs.release_created == 'true' - uses: OneLiteFeatherNET/workflows/.github/workflows/gradle-publish.yml@v2.4.0 + uses: OneLiteFeatherNET/workflows/.github/workflows/gradle-publish.yml@v2.8.1 with: java-version: "25" publish-task: "publish" @@ -51,9 +51,37 @@ jobs: name: Publish snapshot to OneLiteFeatherRepo needs: release-please if: needs.release-please.outputs.release_created != 'true' - uses: OneLiteFeatherNET/workflows/.github/workflows/gradle-publish.yml@v2.4.0 + uses: OneLiteFeatherNET/workflows/.github/workflows/gradle-publish.yml@v2.8.1 with: java-version: "25" build-task: "-Psnapshot build" publish-task: "-Psnapshot publish" secrets: inherit + + sbom: + name: Attach SBOM to release + needs: release-please + if: needs.release-please.outputs.release_created == 'true' + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ needs.release-please.outputs.tag_name }} + + - name: Generate CycloneDX SBOM + uses: aquasecurity/trivy-action@v0.36.0 + with: + scan-type: fs + scan-ref: . + format: cyclonedx + output: bom.json + exit-code: '0' + + - name: Attach SBOM to the release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ needs.release-please.outputs.tag_name }} + run: gh release upload "$TAG" bom.json --clobber diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..d97fcbc --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,55 @@ +name: Security + +# Trivy vulnerability gate plus a CycloneDX SBOM of the repository. Self-contained +# on purpose: it needs no build tool and no registry credentials, so it is the +# baseline security gate for every repository regardless of language. +on: + pull_request: + push: + branches: [main] + schedule: + - cron: "10 6 * * 1" + workflow_dispatch: +permissions: + contents: read + security-events: write + +jobs: + trivy: + name: Trivy scan + uses: OneLiteFeatherNET/workflows/.github/workflows/security-scan.yml@v2.8.1 + with: + scan-type: "fs" + scanners: "vuln,secret" + severity: "CRITICAL,HIGH" + # Report-only for now, so adopting this does not turn CI red on day one. + fail-on-findings: false + upload-sarif: true + secrets: inherit + + sbom: + name: CycloneDX SBOM + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Generate SBOM + uses: aquasecurity/trivy-action@v0.36.0 + with: + scan-type: fs + scan-ref: . + format: cyclonedx + output: bom.json + # An SBOM is an inventory, not a finding list - never fail on it. + exit-code: '0' + + - name: Upload SBOM + uses: actions/upload-artifact@v4 + with: + name: sbom-cyclonedx + path: bom.json + if-no-files-found: error + retention-days: 90 diff --git a/commitlint.config.mjs b/commitlint.config.mjs new file mode 100644 index 0000000..0616fb9 --- /dev/null +++ b/commitlint.config.mjs @@ -0,0 +1,3 @@ +export default { + extends: ['@commitlint/config-conventional'], +}; diff --git a/release-please-config.json b/release-please-config.json index 5739d7f..dc263c3 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -3,14 +3,17 @@ "release-type": "simple", "include-component-in-tag": false, "include-v-in-tag": true, - "bootstrap-sha": "HEAD", + "bootstrap-sha": "cbd74ccb7ecbc6871edb975cf319ed8d94f18155", "pull-request-header": "", "packages": { ".": { "package-name": "falco", "changelog-path": "CHANGELOG.md", "extra-files": [ - { "type": "generic", "path": "build.gradle.kts" } + { + "type": "generic", + "path": "build.gradle.kts" + } ] } } diff --git a/renovate.json b/renovate.json index 65c7c2c..8d88573 100644 --- a/renovate.json +++ b/renovate.json @@ -1,17 +1,13 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ - "github>OneLiteFeatherNET/renovate:default(team:falco-maintainers)", + "github>OneLiteFeatherNET/renovate:default(OneLiteFeatherNET/falco-maintainers)", "github>OneLiteFeatherNET/renovate:minestom" ], - "description": [ - "The argument to the :default preset becomes :reviewer(arg0). It carries the `team:` prefix and the bare slug, without the organisation: Renovate splits reviewers on that prefix and posts the remainder as a team reviewer, so `OneLiteFeatherNET/falco-maintainers` would be sent as a user name and rejected. The team holds admin on this repository and is the same owner .github/CODEOWNERS names.", - "The :minestom flavor only fixes version ordering for a pinned `net.minestom:minestom`. Falco resolves Minestom through mycelium-bom and pins no version of its own today, so the flavor is inert here and kept for the moment a version does get pinned." - ], "customManagers": [ { "customType": "regex", - "description": "Keep the coordinates in the README install snippets on the released version. One rule for all four published modules: the module name is captured rather than templated, so a module is covered the moment a snippet mentions it. `falco-benchmarks` and `falco-demo` are deliberately not listed because they are never published. A consumer declares the BOM inside a `platform(\"…\")` call rather than a bare `implementation(\"…\")` one, so the match string covers both call forms; `falco-bom` and `falco-instance` are listed even though the README currently mentions neither — the quick start declares only `falco-anvil` and `falco-light`, and the full set moved to the Installation page of the wiki, which Renovate cannot reach. That page says so and points at the README as the authority on the current version. Keeping both names here costs nothing and covers the moment either returns to a README snippet; the BOM will also still be in its three-argument form, which this pattern does not match, until it has a first release.", + "description": "Keep the coordinates in the README install snippets on the released version. One rule for all four published modules: the module name is captured rather than templated, so a module is covered the moment a snippet mentions it. `falco-benchmarks` and `falco-demo` are deliberately not listed because they are never published. A consumer declares the BOM inside a `platform(\"\u2026\")` call rather than a bare `implementation(\"\u2026\")` one, so the match string covers both call forms; `falco-bom` and `falco-instance` are listed even though the README currently mentions neither \u2014 the quick start declares only `falco-anvil` and `falco-light`, and the full set moved to the Installation page of the wiki, which Renovate cannot reach. That page says so and points at the README as the authority on the current version. Keeping both names here costs nothing and covers the moment either returns to a README snippet; the BOM will also still be in its three-argument form, which this pattern does not match, until it has a first release.", "managerFilePatterns": [ "/^README\\.md$/" ],