From 2d8a54687a48d2876d9770800a4660269c38a5ad Mon Sep 17 00:00:00 2001 From: Xavier Karma Date: Tue, 20 Oct 2026 15:14:56 +0000 Subject: [PATCH] Initial commit --- .gitea/workflows/ci.yml | 69 +++++++++++++++++++++++++++++++++++++++++ .jscpd.json | 21 +++++++++++++ CI.md | 48 ++++++++++++++++++++++++++++ README.md | 16 ++++++++++ 4 files changed, 154 insertions(+) create mode 100644 .gitea/workflows/ci.yml create mode 100644 .jscpd.json create mode 100644 CI.md create mode 100644 README.md diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..7c5326f --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,69 @@ +name: CI + +on: + pull_request: + push: + branches: [main] + schedule: + - cron: "0 3 * * 1" + workflow_dispatch: + +permissions: + contents: read + +jobs: + security: + runs-on: bongbetic-ci + timeout-minutes: 15 + container: + image: docker.io/semgrep/semgrep:1.178.0 + steps: + - name: Checkout + env: + GITEA_TOKEN: ${{ gitea.token }} + run: | + git init -q . && git remote add origin "${{ gitea.server_url }}/${{ gitea.repository }}.git" && git -c http.extraheader="Authorization: token ${GITEA_TOKEN}" fetch -q --depth=1 origin "${{ gitea.sha }}" && git checkout -q FETCH_HEAD + - name: Semgrep + run: semgrep scan --config p/default --config p/owasp-top-ten --metrics off --error + + lint: + if: gitea.event_name != 'schedule' + runs-on: bongbetic-ci + timeout-minutes: 25 + steps: + - name: Checkout + env: + GITEA_TOKEN: ${{ gitea.token }} + run: | + git init -q . && git remote add origin "${{ gitea.server_url }}/${{ gitea.repository }}.git" && git -c http.extraheader="Authorization: token ${GITEA_TOKEN}" fetch -q --depth=1 origin "${{ gitea.sha }}" && git checkout -q FETCH_HEAD + + # @@LINT_STEPS@@ + # Add your language linter steps above this line (see CI.md), or run + # ci-tools/bin/new-repo-ci.sh with -l python|node|rust to insert them. + + - name: jscpd (duplication, threshold in .jscpd.json) + run: npx --yes jscpd@4.3.0 --config .jscpd.json . + + ai-review: + if: gitea.event_name == 'pull_request' + runs-on: bongbetic-ci + timeout-minutes: 10 + continue-on-error: true + container: + image: docker.io/pragent/pr-agent:0.47.0 + steps: + - name: PR-Agent review (advisory) + shell: sh + env: + CONFIG__GIT_PROVIDER: gitea + GITEA__URL: https://git.bongbetic.com + GITEA__PERSONAL_ACCESS_TOKEN: ${{ secrets.PR_AGENT_GITEA_TOKEN }} + OPENROUTER__KEY: ${{ secrets.OPENROUTER_API_KEY }} + CONFIG__MODEL: ${{ vars.PR_AGENT_MODEL || 'openrouter/anthropic/claude-sonnet-5' }} + CONFIG__CUSTOM_MODEL_MAX_TOKENS: ${{ vars.PR_AGENT_MAX_TOKENS || '200000' }} + run: | + if [ -z "$OPENROUTER__KEY" ] || [ -z "$GITEA__PERSONAL_ACCESS_TOKEN" ]; then + echo "::notice::PR-Agent skipped: OPENROUTER_API_KEY / PR_AGENT_GITEA_TOKEN not available (unset, or PR from a fork)." + exit 0 + fi + pr-agent --pr_url="${{ gitea.event.pull_request.html_url }}" review diff --git a/.jscpd.json b/.jscpd.json new file mode 100644 index 0000000..df53728 --- /dev/null +++ b/.jscpd.json @@ -0,0 +1,21 @@ +{ + "threshold": 5, + "minLines": 5, + "minTokens": 50, + "reporters": ["console"], + "gitignore": true, + "ignore": [ + "**/target/**", + "**/.git/**", + "**/.venv/**", + "**/node_modules/**", + "**/__pycache__/**", + "**/dist/**", + "**/build/**", + "**/*.lock", + "**/package-lock.json", + "**/*.md", + "docs/**" + ], + "path": ["."] +} diff --git a/CI.md b/CI.md new file mode 100644 index 0000000..5aceead --- /dev/null +++ b/CI.md @@ -0,0 +1,48 @@ +# CI + +Gitea Actions workflow: `.gitea/workflows/ci.yml`. Runs on the self-hosted `bongbetic-ci` runner. + +| Job | What | Blocks merge | +|---|---|---| +| `security` | Semgrep CE (`p/default`, `p/owasp-top-ten`, `--metrics off --error`) | yes | +| `lint` | Language linter(s) for this repo + `jscpd` duplication check (`.jscpd.json`) | yes | +| `ai-review` | PR-Agent review comment. Advisory only. | no | + +Triggers: pull requests, pushes to `main`, a weekly scheduled run (Mondays 03:00, `security` only; it catches new +Semgrep registry rules), and manual `workflow_dispatch`. + +Branch protection (once set) requires `CI / security (pull_request)` and `CI / lint (pull_request)`. + +## Run locally + +```sh +# Semgrep +podman run --rm -v "$PWD:/src:ro,Z" -w /src docker.io/semgrep/semgrep:1.178.0 \ + semgrep scan --config p/default --config p/owasp-top-ten --metrics off --error + +# Duplication +npx --yes jscpd@4.3.0 --config .jscpd.json . +``` + +Run your language linter the same way the `lint` job does (see the steps in `ci.yml`). + +## Secrets and variables + +Add in Gitea (repo or user settings). Never commit them. + +- `OPENROUTER_API_KEY` (secret): LLM key for PR-Agent. +- `PR_AGENT_GITEA_TOKEN` (secret): token of the comment-only bot account. +- `PR_AGENT_MODEL`, `PR_AGENT_MAX_TOKENS` (optional variables). + +Without the two secrets `ai-review` skips with a notice and the PR is not blocked. + +## Notes + +- Semgrep registry rules are fetched at run time and cannot be pinned. +- Tool and image versions in `ci.yml` are pinned. Bump them on purpose, in a PR. +- Silence a Semgrep finding only with a narrow `# nosemgrep: -- ` on that line. + +## Roll back + +Revert the PR that added the workflow. If branch protection requires these checks, remove the required +checks first (Settings, Branches), or the revert PR cannot merge. diff --git a/README.md b/README.md new file mode 100644 index 0000000..a3f50c0 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# ci-template + +Gitea template repo. Create a new repo with **Use this template** (tick "Git Content") to start with the Bongbetic CI +quality gates already in place: `.gitea/workflows/ci.yml`, `.jscpd.json`, `CI.md`. + +After creating the repo: + +1. Add your language linter steps in the `lint` job (marker `# @@LINT_STEPS@@` in `ci.yml`). Snippets for Python, + Node and Rust live in the `ci-tools` repo under `snippets/`. +2. Add the secrets listed in `CI.md`. +3. After the first CI run, require `CI / security (pull_request)` and `CI / lint (pull_request)` on `main` + (`ci-tools/bin/new-repo-ci.sh --protect-only `, or Settings, Branches). + +For repos that already exist, use `ci-tools/bin/new-repo-ci.sh`, which opens a PR instead. + +Delete this README in the new repo.