$schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
# Protected-file rules — secret detection and git/repo safety. Absorbed from
# ts-libs/.spur/rules/structure/protected-files.yaml, re-scoped for apps/** +
# packages/** + scripts/** (release/dev tooling is a prime secret-leak site).
# Mirrors the AGENTS.md safety boundaries (no secrets, no .env, no unreviewed
# workflows, no destructive git).
rules:
  - id: no-hardcoded-secrets
    description: "Hardcoded secrets detected; read secrets from environment/config boundaries instead. Spur never stores agent API keys (AGENTS.md)."
    severity: error
    evaluator:
      type: secrets-scanner
      config:
        categories: [api-key, token, private-key, password, connection-string]
        # The secrets-scanner uses the in-process LOOSE matcher (substring/suffix
        # fragments), not ripgrep globs. Deep globs like `apps/**/*.ts` collapse to
        # `apps/.ts` and match NOTHING — so scope must be path FRAGMENTS:
        # `apps/`, `packages/`, `scripts/` cover all TS source via substring match.
        scope:
          include:
            - "apps/"
            - "packages/"
            - "scripts/"
          exclude:
            - "/tests/"
            - ".test.ts"
            # nested engine scratch dirs under the included app/package trees;
            # root .spur/ is outside this rule's include scope
            # `/`.spur/` is load-bearing: the secrets-scanner's in-process walker
            # does NOT skip dot-dirs, so nested .spur/ scratch dirs under app/package
            # trees are scanned. `vendors/` fires today (LOOSE include fragments match
            # `vendors/*/scripts/**`), so it must stay excluded.
            - "/.spur/"
            - "vendors/"
            # `apps/cli/config/` is the gitignored bundle-config output (.gitignore
            # `bundle-config`); it duplicates config/workflows YAML, which is outside
            # this rule's include scope — scanning generated copies only adds noise
            # (e.g. `id: task-implement-transition` trips the sk- token shape).
            - "apps/cli/config/"

  - id: no-unsafe-git-commands
    description: "Unsafe git commands (force-push, hard reset) can overwrite history or cause data loss (AGENTS.md CRITICAL safety)."
    severity: error
    evaluator:
      type: rg
      config:
        pattern: "git\\s+.*(push\\s+.*--force|push\\s+.*--force-with-lease\\b)|git\\s+.*reset\\s+--hard\\b"
    include:
      - "**/*.sh"
      - "**/*.bash"
      - "scripts/**/*.ts"
      - "package.json"
      - ".github/**/*.yml"
      - ".github/**/*.yaml"

  - id: no-env-files
    description: ".env files must not be committed; use checked-in examples only (AGENTS.md: never commit .env*)."
    severity: error
    evaluator:
      type: path
      config:
        must: absent
    include:
      - "**/.env"
      - "**/.env.*"
    exclude:
      - "**/.env.example"

# NOTE: the ts-libs `no-github-workflows` rule (asserting .github/workflows must be
# ABSENT) was intentionally NOT absorbed — ts-libs is a library repo with no CI,
# but Spur is an application repo that legitimately ships ci.yml + publish.yml.
# "Never edit workflows without approval" (AGENTS.md) is a process rule for agents,
# not a file-absence assertion.
