# Security & the Safety Model ## Non-destructive by design URGithub **never** runs destructive Git operations. It will not `reset`, force-push (`--force`), rebase, or clean your working tree — under any trigger, ever. ```mermaid flowchart LR A{Inspection} -->|SAFE| B[CONTINUE] A -->|UNSAFE| C[BLOCK] C --> D[REPORT] ``` The synchronize operation is deliberately conservative: ```bash git fetch git pull --ff-only # fast-forward only git commit # only when the policy allows git push ``` Authorization is checked **separately** from authentication — having a valid login does not mean a repository is pushable, and the two are verified independently. ## GitHub authentication & permissions URGithub authenticates through your GitHub CLI session — it does **not** store or use its own GitHub credentials. - **`repo` scope required.** The registration check requires the `repo` scope on the authenticated `gh` token. Verify with `gh auth status`. - **Never place tokens in config files.** Do not copy or manually put GitHub tokens, passwords, private keys, or cloud credentials into URGithub configuration files. URGithub uses the authenticated GitHub CLI session instead. - **Git identity ≠ GitHub credentials.** The `user.name` / `user.email` you configure in Git are only the *author identity* used for commits — they are not your GitHub authentication. ## Secret detection Every file is scanned before anything is pushed. Secrets are matched two ways (both configured under `security.*`): ### Filename patterns ``` .env* *.pem *.key credentials.json secrets.json *.p12 ``` ### Content patterns (regex) | What it catches | Example pattern | |---|---| | Private keys | `-----BEGIN [A-Z ]*PRIVATE KEY-----` | | GitHub tokens | `gh[opsur]_[A-Za-z0-9]{20,}` | | AWS access keys | `AKIA[0-9A-Z]{16}` | | Google API keys | `AIza[0-9A-Za-z\-_]{35}` | | Slack tokens | `xox[baprs]-[0-9A-Za-z\-]{10,}` | | Stripe live keys | `sk_live_[0-9A-Za-z]{20,}` | | Generic API keys | `sk-[A-Za-z0-9_\-]{24,}` | | Inline secrets | `(?i)(api_key|secret|password|token)\s*[:=]\s*"..."` | Files larger than `security.max_scan_bytes` (default 1 MB) are not fully scanned. Add exceptions via `security.allow_files` — globs excluded from **both** the filename check and the content check — when you are certain a match is a false positive. ## CI/CD security gates The runtime checks above protect every repository URGithub manages. The URGithub codebase itself is additionally guarded by two GitHub Actions workflows: | Workflow | What it scans | Fails on | |---|---|---| | `codeql.yml` — CodeQL Advanced | Python and Actions code, `security-extended` + `security-and-quality` query suites | New security vulnerabilities | | `secret-scan.yml` — gitleaks | Full commit history for hardcoded secrets | Any secret found in any commit | - Both run on push and pull requests against `main`; CodeQL also runs on a weekly schedule. - A secret that reaches `main` still fails the gitleaks job — rotate it immediately, even when the scan catches it. ## File size limits | Setting | Default | Behavior | |---|---|---| | `limits.warn_file_mb` | 50 MB | Warned in the report | | `limits.max_file_mb` | 100 MB | Blocks sync when `block_on_oversize` is on (default) | ## When a repository is **not** pushed Synchronization stops and reports when any of these are detected. Each case is journaled and visible in `report.html`: | Result | What it means | |---|---| | `blocked: secrets` | Secret patterns detected — by filename **and** file content | | `blocked: oversize files` | Files over the hard size limit | | `blocked: divergence` | Local and remote histories diverged — never merged automatically | | `blocked: remote unreachable` | Remote inaccessible | | `blocked: no push permission` | Authorization failure — no permission to push | | `blocked: no remote configured` | No `origin` remote | | `blocked: missing` | Folder missing / not a git repo / quarantined | | `skipped` | Dirty tree without `commit_policy.auto_commit` — never silently commits | | `failed` | Fetch / `git add` / commit / push fails (journaled with the reason) | A blocked operation is an **intentional safety result**, not a bug. Do not bypass it — inspect `report.html` first. One bad repo never blocks the others. ## The four safety rules | Rule | Why it exists | |---|---| | **Rule 0** — No registration → no operations | Unregistered runs only show the setup wizard; nothing else runs | | **Rule 1** — No scan → no sync | The sync engine only touches repositories scanned in the same run | | **Rule 2** — Every run produces a report | Failures and blocks are always visible, never silent | | **Rule 3** — Trigger type does not matter | Scheduled and automatic runs use the same safe pipeline as manual ones | ## Deleted / renamed repository policy URGithub will not act on a locally deleted repository without a confirmation chain: - `deleted_repo_policy.confirm_scans` — **3** consecutive scans must flag it. - `deleted_repo_policy.confirm_days` — **7** days must pass. - `deleted_repo_policy.require_remote_confirmation` — the remote must confirm deletion. - `deleted_repo_policy.require_user_confirmation` — you must explicitly confirm. ## Recommendations - Never commit credentials or secrets into any repository — block-on-secrets is the last line of defense. Never commit `.env` files, private keys, GitHub tokens, password files, cloud credentials, or API keys unless they are intentional test values with no security impact. - Use the least-privilege GitHub token/permission set URGithub can work with — grant the GitHub account and tools only the permissions necessary for the repositories you intend to manage. - Keep the runtime directory (`urgithub\.urgithub`) protected — it holds configuration, registry, and reports. Use normal operating-system permissions to restrict access. - Review `report.html` for blocked operations before investigating further — investigate the reason instead of disabling the protection blindly. - Rotate any secret that was ever pushed, even once. ## Reporting a vulnerability - Secret detection is on by default (`security.block_on_secrets`). Anything flagged is reported and **never pushed**. - To report a vulnerability, open a **private advisory** on GitHub or email the maintainer. - **Do not post keys or secrets in issues.** When reporting a problem, redact GitHub tokens, passwords, private keys, personal access tokens, and private repository contents before opening an issue. Next: [Report & Journal](report.md) — everything the report and journal record.