diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..9f8d869 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,56 @@ +--- +name: Lint + +on: + pull_request: + +# Read-only: this workflow only inspects code and reports status, so it works +# from fork PRs (which receive a read-only token and no secrets). +permissions: + contents: read + +concurrency: + group: lint-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + pre-commit: + name: pre-commit (changed files) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-python@v5 + with: + python-version: '3.x' + - name: Run pre-commit on changed files + # gitleaks is handled by the dedicated job below (it scans git history, + # not a file list), so skip it here to avoid a redundant no-op run. + env: + SKIP: gitleaks + BASE_SHA: ${{ github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: | + python -m pip install --upgrade pre-commit + pre-commit run \ + --from-ref "$BASE_SHA" \ + --to-ref "$HEAD_SHA" \ + --show-diff-on-failure + + gitleaks: + name: gitleaks (secret scan) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Scan PR commits for secrets + env: + GITLEAKS_VERSION: 8.30.1 + BASE_SHA: ${{ github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: | + curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \ + | tar -xz gitleaks + ./gitleaks git . --redact --no-banner --log-opts="${BASE_SHA}..${HEAD_SHA}" diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 0000000..2d4c385 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,49 @@ +# Gitleaks configuration for JimsGarage. +# +# These are homelab tutorial configs: many directories intentionally ship +# throwaway/dummy credentials so viewers can copy a working example (see +# issue #127). This config keeps the full default secret-detection ruleset +# but allowlists the paths and placeholder values that are dummy *by +# convention*, so the scanner only fires on something that looks like a +# genuine accidental leak. +# +# Tradeoff worth knowing: because `.env` files here are demo placeholders by +# design, they are allowlisted wholesale — gitleaks will NOT catch a real +# secret accidentally dropped into a `.env`. The scanner's value in this repo +# is catching real secrets pasted into scripts, compose files, and manifests. + +title = "JimsGarage gitleaks config" + +[extend] +# Inherit all of gitleaks' built-in rules (AWS keys, JWTs, private keys, +# provider tokens, high-entropy strings, etc.). +useDefault = true + +[[allowlists]] +description = "Intentional throwaway credentials in example/placeholder files" +# `paths` is matched against the file path of the candidate finding. +paths = [ + # Tracked .env files are demo placeholders by convention in this repo. + '''(^|/)\.env$''', + '''\.env$''', + # Files that are explicitly named as examples/samples/templates. + '''(^|/)[^/]*example[^/]*''', + '''(^|/)[^/]*sample[^/]*''', + '''\.(example|sample|dist|template|tmpl)$''', +] + +[[allowlists]] +description = "Common placeholder secret values" +# `regexes` is matched against the detected secret value itself, so a +# realistic-looking value anywhere still gets flagged — only obvious +# placeholders are exempted. +regexTarget = "match" +regexes = [ + '''(?i)changeme''', + '''(?i)your[-_].*(key|token|secret|password)''', + '''(?i)example[-_.]?(key|token|secret|password|value)?''', + '''(?i)supersecret''', + '''(?i)redacted''', + '''(?i)<[^>]+>''', # angle-bracket placeholders like + '''(?i)^(test|dummy|placeholder|password|secret)$''', +] diff --git a/.gitleaksignore b/.gitleaksignore new file mode 100644 index 0000000..bd198ad --- /dev/null +++ b/.gitleaksignore @@ -0,0 +1,41 @@ +# gitleaks baseline — pre-existing intentional dummy credentials kept here +# instead of an inline `# gitleaks:allow` annotation. A finding is baselined +# (rather than annotated inline) when its file cannot or should not be edited: +# - JSON files have no comment syntax (e.g. Netbird/management.json) +# - multi-line PEM private-key blocks can't carry a reliable inline marker +# (Authelia/Authelia/configuration.yml) +# - files with pre-existing lint debt: editing them would pull that file into +# the changed-files lint scope and fail unrelated yamllint/hygiene checks. +# +# New intentional dummies in clean, comment-capable files should use an inline +# `# gitleaks:allow` instead of being added here. See CONTRIBUTING.md. + +Authelia/Authelia/configuration.yml:generic-api-key:19 +Authelia/Authelia/configuration.yml:generic-api-key:226 +Authelia/Authelia/configuration.yml:private-key:369 +Authelia/Authelia/configuration.yml:generic-api-key:681 +Authelia/Authelia/configuration.yml:private-key:790 +Authelia/Authelia/configuration.yml:generic-api-key:872 +Authelia/Authelia/configuration.yml:private-key:962 +Authelia/Authelia/configuration.yml:private-key:1068 +Authelia/Authelia/configuration.yml:private-key:1225 +Authelia/Authelia/configuration.yml:generic-api-key:1267 +Authelia/Authelia/configuration.yml:private-key:1314 +Grafana-Monitoring/Part-2/telegraf.conf:generic-api-key:398 +Home-Assistant/docker-compose.yaml:generic-api-key:43 +Netbird/docker-compose.yml:generic-api-key:15 +Netbird/docker-compose.yml:generic-api-key:16 +Netbird/management.json:generic-api-key:19 +Netbird/management.json:generic-api-key:30 +Netbird/management.json:generic-api-key:35 +Netbird/management.json:generic-api-key:52 +Paperless-ngx/docker-compose.yaml:generic-api-key:83 +Popup-Homelab/docker-compose.yaml:generic-api-key:87 +Pterodactyl/config.yml:generic-api-key:3 +Pterodactyl/config.yml:generic-api-key:4 +Synapse/docker-compose.yaml:generic-api-key:57 +Synapse/homeserver.yaml:generic-api-key:29 +Synapse/mautrix-discord-bridge/docker-compose.yaml:generic-api-key:36 +Terraform/providers.tf:generic-api-key:14 +Vikunja/docker-compose.yaml:generic-api-key:13 +Zitadel/docker-compose.yaml:generic-api-key:10 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 615bc75..4a1000e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,13 +1,40 @@ --- repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v5.0.0 hooks: + # Pre-existing checks - id: check-symlinks - id: destroyed-symlinks - id: detect-aws-credentials args: [--allow-missing-credentials] + # General hygiene + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-merge-conflict + - id: check-added-large-files + - id: mixed-line-ending + - id: check-yaml + args: [--allow-multiple-documents] - repo: https://github.com/IamTheFij/docker-pre-commit rev: v3.0.1 hooks: - id: docker-compose-check + - repo: https://github.com/koalaman/shellcheck-precommit + rev: v0.10.0 + hooks: + - id: shellcheck + # Block on real warnings/errors; skip style/info noise on legacy scripts. + args: [--severity=warning] + - repo: https://github.com/adrienverge/yamllint + rev: v1.35.1 + hooks: + - id: yamllint + - repo: https://github.com/rhysd/actionlint + rev: v1.7.7 + hooks: + - id: actionlint + - repo: https://github.com/gitleaks/gitleaks + rev: v8.30.1 + hooks: + - id: gitleaks diff --git a/.yamllint.yaml b/.yamllint.yaml new file mode 100644 index 0000000..5fe29e9 --- /dev/null +++ b/.yamllint.yaml @@ -0,0 +1,21 @@ +--- +# Lenient ruleset: this repo has a large body of pre-existing YAML (compose +# stacks, k8s manifests, Ansible). The goal is to catch real problems on +# changed files without drowning contributors in stylistic noise. +extends: default + +rules: + # Long lines are common and harmless in compose/k8s/Ansible YAML. + line-length: disable + # Many files intentionally omit the leading '---'. + document-start: disable + # compose/Ansible use yes/no/on/off as values, not just true/false. + truthy: + check-keys: false + # Indentation styles vary across the repo; only require internal consistency. + indentation: + spaces: consistent + indent-sequences: whatever + comments: + min-spaces-from-content: 1 + comments-indentation: disable