From 002913c20ed8978d6575ef049caea66c467fbd98 Mon Sep 17 00:00:00 2001 From: Amaury Ricardo Date: Wed, 1 Jul 2026 14:42:58 -0300 Subject: [PATCH 1/6] feat(cr): add pre-push hook --- .pushgate.yml | 190 ++++++++++++++++++++++++++++++++++++++++++++++ README-project.md | 23 ++++++ README.md | 23 ++++++ 3 files changed, 236 insertions(+) create mode 100644 .pushgate.yml diff --git a/.pushgate.yml b/.pushgate.yml new file mode 100644 index 000000000..bc02c1aa6 --- /dev/null +++ b/.pushgate.yml @@ -0,0 +1,190 @@ +# ============================================================================= +# Pushgate v2 configuration - full reference +# https://github.com/rootstrap/ai-pushgate +# ============================================================================= +# Commit .pushgate.yml so the team shares review settings. +# +# To install or update Pushgate: +# curl -fsSL https://raw.githubusercontent.com/rootstrap/ai-pushgate/main/install.sh | bash +# +# Reinstall with a pre-built template when useful: +# curl -fsSL https://raw.githubusercontent.com/rootstrap/ai-pushgate/main/install.sh | bash -s -- --template node +# curl -fsSL https://raw.githubusercontent.com/rootstrap/ai-pushgate/main/install.sh | bash -s -- --template typescript +# curl -fsSL https://raw.githubusercontent.com/rootstrap/ai-pushgate/main/install.sh | bash -s -- --template nextjs +# curl -fsSL https://raw.githubusercontent.com/rootstrap/ai-pushgate/main/install.sh | bash -s -- --template ruby +# curl -fsSL https://raw.githubusercontent.com/rootstrap/ai-pushgate/main/install.sh | bash -s -- --template rails +# ============================================================================= + +version: 2 + +ai: + # Supported modes: blocking, advisory, off. + mode: advisory + + # Changed-line overages block the push; prompt-token overages skip local AI. + max_changed_lines: 500 + max_prompt_tokens: 12000 + timeout_seconds: 120 + + # Blocking and advisory modes select a provider and define its matching block. + provider: claude + providers: + # Provider-specific settings are kept below the provider name. + claude: + model: claude-sonnet-4-20250514 + # To use the standalone GitHub Copilot CLI, set provider: copilot and + # uncomment this block. Omit model to let Copilot choose its default. + # copilot: + # model: auto + +review: + # Branch to diff against when collecting changes. + target_branch: master + + # Lines of surrounding context included in the diff sent to the provider. + context_lines: 10 + + # Below this changed-line threshold, later AI work can send full file context. + max_lines_for_full_file: 300 + +# ============================================================================= +# Tools +# ============================================================================= +# Tools run before AI review. Each command is an argv array, not a shell string. +# A {changed_files} token expands to individual argv entries without shell +# interpolation, so filenames with spaces stay one argument. +# +# Tool defaults: +# timeout_seconds: 60 +# mode: blocking # blocking | warning; warnings require confirmation +# run: changed_files # changed_files | always +# fail_fast: true +# +# Examples (uncomment and adapt as needed): +# +# tools: +# - name: eslint +# command: ["npx", "eslint", "{changed_files}"] +# extensions: [".js", ".jsx", ".ts", ".tsx", ".mjs"] +# timeout_seconds: 60 +# mode: blocking +# run: changed_files +# fail_fast: true +# +# - name: prettier +# command: ["npx", "prettier", "--check", "{changed_files}"] +# extensions: [".js", ".jsx", ".ts", ".tsx", ".mjs", ".json", ".css", ".md"] +# +# - name: rubocop +# command: ["bundle", "exec", "rubocop", "{changed_files}"] +# extensions: [".rb", ".rake", ".gemspec"] +# +# - name: brakeman +# command: ["bundle", "exec", "brakeman", "--no-pager"] +# run: always +# +# - name: pytest +# command: ["pytest", "--tb=short"] +# extensions: [".py"] +# +tools: + - name: type-check + command: ["pnpm", "run", "type-check"] + run: always + timeout_seconds: 120 + mode: blocking + fail_fast: true + + - name: lint + command: ["pnpm", "run", "lint"] + run: always + timeout_seconds: 120 + mode: blocking + fail_fast: true + + - name: lint-translations + command: ["pnpm", "run", "lint:translations"] + run: always + timeout_seconds: 120 + mode: blocking + fail_fast: true + +# ============================================================================= +# Built-in deterministic policies +# ============================================================================= +# Built-ins are opt-in local checks that do not require external tools. +# +# Policy defaults: +# mode: blocking # blocking | warning; warnings require confirmation +# +# Examples (uncomment and adapt as needed): +# +# policies: +# diff_size: +# max_changed_lines: 500 +# mode: warning # asks before continuing +# fail_fast: false # if blocking, continue later checks after a violation +# +# forbidden_paths: +# patterns: +# - ".env" +# - ".env.*" +# - "secrets/**" +# - "*.pem" +# mode: blocking +# fail_fast: true +# +policies: + diff_size: + max_changed_lines: 500 + mode: warning + fail_fast: false + + forbidden_paths: + patterns: + - ".env" + - ".env.*" + - "secrets/**" + - "*.pem" + mode: blocking + fail_fast: true + +# ============================================================================= +# Plugins +# ============================================================================= +# Plugin adapters run external scanners through a first-class Pushgate result +# model. They run after built-in policies and before generic tools. +# +# Gitleaks scans the branch commit range for secrets before push. Install it +# separately (for example, brew install gitleaks) and tune rules with +# .gitleaks.toml, .gitleaksignore, or a baseline report. +# +# plugins: +# gitleaks: +# enabled: true +# command: gitleaks +# timeout_seconds: 60 +# mode: blocking +# fail_fast: true +# config_path: .gitleaks.toml +# baseline_path: .gitleaks/baseline.json +# gitleaks_ignore_path: .gitleaksignore +# +plugins: {} + +# ============================================================================= +# Ignore paths +# ============================================================================= +# Files and patterns excluded from tool checks and AI review. +ignore_paths: + - "*.lock" + - "package-lock.json" + - "pnpm-lock.yaml" + - "yarn.lock" + - "Gemfile.lock" + - "dist/**" + - "build/**" + - ".next/**" + - "coverage/**" + - "tmp/**" + - "log/**" diff --git a/README-project.md b/README-project.md index becde97db..417679f32 100644 --- a/README-project.md +++ b/README-project.md @@ -59,6 +59,29 @@ To build your app locally you can run any of the build scripts with --local. `pnpm build:development:ios --local` +## Pushgate + +This repository uses `ai-pushgate` from `.git/hooks/pre-push` to run local checks before `git push`. + +Pushgate setup for template users: +- `.pushgate.yml` is versioned, so everyone gets the same rules. +- `.git/hooks/pre-push` is local and is not committed to Git. +- Each developer must install Pushgate once per clone. + +Install from repo root: +```sh +curl -fsSL https://raw.githubusercontent.com/rootstrap/ai-pushgate/main/install.sh | bash +``` + +Verify the hook was created: +```sh +ls .git/hooks/pre-push +``` + +How to skip checks: +> Skip AI only: `git -c pushgate.skip-ai-check=true push` +> Skip everything: `git push --no-verify` + ### SonarQube setup SonarQube is an open-source platform for continuous inspection of code quality. It performs automatic reviews to detect bugs, code smells, and security vulnerabilities. Rootstrap has a SonarQube instance to improve the quality of the software we develop. On each PR, a GitHub Action is triggered to perform the analysis. To set up SonarQube correctly, you need to add the `SONAR_TOKEN`, `SONAR_URL`, and `SONAR_PROJECT` secrets to the repository. Additionally, you must select the quality gate named `ReactNativeTemplate` for your project on SonarQube. In case you're using this project outside Rootstrap and you're not planning to use SonarQube the sonar scanner [workflow](.github/workflows/sonar.yml) should be deleted. diff --git a/README.md b/README.md index a93fddb37..36266dcb3 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,29 @@ The bot will be triggered on issues, pull requests and comments, you can modify Check this [file](https://github.com/rootstrap/rs-gpt-review/blob/main/.github/workflows/main.yml) for more examples. +## Pushgate + +This repository uses `ai-pushgate` from `.git/hooks/pre-push` to run local checks before `git push`. + +Pushgate setup for template users: +- `.pushgate.yml` is versioned, so everyone gets the same rules. +- `.git/hooks/pre-push` is local and is not committed to Git. +- Each developer must install Pushgate once per clone. + +Install from repo root: +```sh +curl -fsSL https://raw.githubusercontent.com/rootstrap/ai-pushgate/main/install.sh | bash +``` + +Verify the hook was created: +```sh +ls .git/hooks/pre-push +``` + +How to skip checks: +> Skip AI only: `git -c pushgate.skip-ai-check=true push` +> Skip everything: `git push --no-verify` + ## πŸ’Ž Libraries used From 6cf7fead91fcc95d44d4bb2745e3a4a3a4fca967 Mon Sep 17 00:00:00 2001 From: Amaury Ricardo Date: Wed, 1 Jul 2026 15:06:56 -0300 Subject: [PATCH 2/6] feat(cr): install pre-push tool in the installation cli --- README-project.md | 3 ++- README.md | 3 ++- cli/index.js | 9 ++++++++- cli/setup-project.js | 17 +++++++++++++++-- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/README-project.md b/README-project.md index 417679f32..607205b1e 100644 --- a/README-project.md +++ b/README-project.md @@ -66,7 +66,8 @@ This repository uses `ai-pushgate` from `.git/hooks/pre-push` to run local check Pushgate setup for template users: - `.pushgate.yml` is versioned, so everyone gets the same rules. - `.git/hooks/pre-push` is local and is not committed to Git. -- Each developer must install Pushgate once per clone. +- If you create the app with `create-rootstrap-rn-app`, Pushgate is installed automatically during setup. +- For existing clones, or if the hook is missing, install it manually: Install from repo root: ```sh diff --git a/README.md b/README.md index 36266dcb3..30b777574 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,8 @@ This repository uses `ai-pushgate` from `.git/hooks/pre-push` to run local check Pushgate setup for template users: - `.pushgate.yml` is versioned, so everyone gets the same rules. - `.git/hooks/pre-push` is local and is not committed to Git. -- Each developer must install Pushgate once per clone. +- If you create the app with `create-rootstrap-rn-app`, Pushgate is installed automatically during setup. +- For existing clones, or if the hook is missing, install it manually: Install from repo root: ```sh diff --git a/cli/index.js b/cli/index.js index 2d3bd1d36..35f2bc4c0 100755 --- a/cli/index.js +++ b/cli/index.js @@ -3,7 +3,11 @@ const { consola } = require('consola'); const { showMoreDetails } = require('./utils.js'); const { cloneLatestTemplateRelease } = require('./clone-repo.js'); -const { setupProject, installDependencies } = require('./setup-project.js'); +const { + setupProject, + installDependencies, + installPushgate, +} = require('./setup-project.js'); const pkg = require('./package.json'); const { name: packageName } = pkg; @@ -27,6 +31,9 @@ const createRootstrapApp = async () => { // install project dependencies using pnpm await installDependencies(projectName); + // install Pushgate hook (best-effort) + await installPushgate(projectName); + // show instructions to run the project + link to the documentation showMoreDetails(projectName); }; diff --git a/cli/setup-project.js b/cli/setup-project.js index cbde3776b..5cc0c70f0 100755 --- a/cli/setup-project.js +++ b/cli/setup-project.js @@ -1,8 +1,6 @@ const { execShellCommand, runCommand, - UPSTREAM_REPOSITORY, - TEMPLATE_REPOSITORY, } = require('./utils.js'); const { consola } = require('consola'); const fs = require('fs-extra'); @@ -25,6 +23,20 @@ const installDependencies = async (projectName) => { }); }; +const installPushgate = async (projectName) => { + consola.start('Installing Pushgate pre-push hook'); + try { + await execShellCommand( + `cd ${projectName} && curl -fsSL https://raw.githubusercontent.com/rootstrap/ai-pushgate/main/install.sh | bash` + ); + consola.success('Pushgate pre-push hook installed'); + } catch (error) { + consola.warn( + 'Could not auto-install Pushgate. Run installer manually from the project root.' + ); + } +}; + const removeUnrelatedFiles = () => { projectFilesManager.removeFiles([ '.git', @@ -227,4 +239,5 @@ const setupProject = async (projectName) => { module.exports = { setupProject, installDependencies, + installPushgate, }; From 9746e581a2c1c9caef6cfc8e9abcd0e87aec3726 Mon Sep 17 00:00:00 2001 From: Amaury Ricardo Date: Wed, 1 Jul 2026 15:24:29 -0300 Subject: [PATCH 3/6] feat(pushgate): add eslint and test tools --- .pushgate.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.pushgate.yml b/.pushgate.yml index bc02c1aa6..d03b3ec67 100644 --- a/.pushgate.yml +++ b/.pushgate.yml @@ -95,6 +95,14 @@ tools: mode: blocking fail_fast: true + - name: eslint + command: ["pnpm", "exec", "eslint", "{changed_files}"] + extensions: [".js", ".jsx", ".ts", ".tsx", ".mjs"] + run: changed_files + timeout_seconds: 120 + mode: blocking + fail_fast: true + - name: lint command: ["pnpm", "run", "lint"] run: always @@ -109,6 +117,13 @@ tools: mode: blocking fail_fast: true + - name: test + command: ["pnpm", "run", "test"] + run: always + timeout_seconds: 120 + mode: blocking + fail_fast: true + # ============================================================================= # Built-in deterministic policies # ============================================================================= From b653099386f775ecb72b035bcd12a15db491769f Mon Sep 17 00:00:00 2001 From: Amaury Ricardo Date: Wed, 1 Jul 2026 15:29:53 -0300 Subject: [PATCH 4/6] feat(skill): update cr description to add risk labels --- .agents/skills/pr-description/SKILL.md | 10 ++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 19 +++++++++++++++++++ README-project.md | 17 +++++++++++++++++ README.md | 17 +++++++++++++++++ 4 files changed, 63 insertions(+) diff --git a/.agents/skills/pr-description/SKILL.md b/.agents/skills/pr-description/SKILL.md index f9b0fac9c..c6486c782 100644 --- a/.agents/skills/pr-description/SKILL.md +++ b/.agents/skills/pr-description/SKILL.md @@ -62,6 +62,16 @@ Write 1-3 concise sentences explaining the reason for the change. Tie it to the Name affected screens, flows, platforms, users, modules, or developer workflows. Use a short sentence or compact bullets. If impact is unclear, leave a placeholder comment instead of guessing. +### Risk Classification + +Add the appropriate `risk:*` label when the PR is opened. If the label is unknown, escalate instead of guessing. + +- `risk:low` for config, copy, or minor UI tweaks with low blast radius. +- `risk:medium` for feature work or refactors touching multiple files. +- `risk:high` for auth, payments, migrations, or security-sensitive code. + +If the branch or user request does not make the risk obvious, leave the template placeholder and call out the uncertainty in Notes. + ### How did you test this? List commands run and manual checks performed. Keep the existing checklist from the template and check only items that are supported by evidence or explicitly provided by the user. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a0878d3de..bfe6fc5da 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -35,6 +35,25 @@ _**Why** did you make these changes? This is your opportunity to provide the rat _Does your code affect something downstream? Are there side effects people should know about? Tag any developers that should be kept abreast of this change._ --> +--- + +### Layer 2: Risk Classification + +Author applies a risk label when opening the PR. When in doubt, escalate. + +| Label | When to use | +| --- | --- | +| `risk:low` | Config, copy, minor UI tweaks. Low blast radius. | +| `risk:medium` | Feature work, refactors touching multiple files. | +| `risk:high` | Auth, payments, migrations, security-sensitive code. | + +**Setup** + +- [ ] Create `risk:low`, `risk:medium`, `risk:high` labels in the repo +- [ ] Add risk criteria to contributing guide or PR template +- [ ] Add reminder in PR template to apply the label before requesting review +- [ ] Define who can override/escalate (suggested: tech lead) + ## How did you test this?