Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# >>> BEGIN petry-projects secrets baseline (managed by .github — do not edit) >>>
# ============================================================================
# petry-projects baseline .gitignore — SECRETS ONLY
# ----------------------------------------------------------------------------
Expand Down Expand Up @@ -394,3 +395,10 @@ actionlint.tar.gz
# ============================================================================
# End of petry-projects secrets baseline
# ============================================================================
# <<< END petry-projects secrets baseline <<<
#
# L2 — ecosystem/OS extension (per-repo, free to edit): append language,
# framework, and OS entries BELOW this line from the matching template at
# https://github.com/github/gitignore. Never edit inside the markers above,
# and never re-ignore a path the L1 block negates. See
# standards/gitignore-standard.md.
103 changes: 103 additions & 0 deletions standards/gitignore-standard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# .gitignore Standard

**Status:** Required
**Applies to:** All repos in `petry-projects` org
**Enforced by:** [`compliance-audit.sh`](../scripts/compliance-audit.sh) (`pp_check_gitignore_secrets_block`, in [`scripts/lib/push-protection.sh`](../scripts/lib/push-protection.sh))

Every repository's `.gitignore` starts from the org-managed **secrets baseline**
maintained in this repo at [`/.gitignore`](../.gitignore). This standard is the
first layer of defense in the [Push Protection Standard](push-protection.md):
it keeps credentials out of the working tree before any of the scanning layers
(GitHub push protection, gitleaks pre-commit, CI gitleaks) ever run.

## Two-Layer Model

A compliant `.gitignore` has exactly two layers, in this order:

| Layer | Name | Ownership | Editable? |
|-------|------|-----------|-----------|
| **L1** | Secrets baseline | Org-managed (this repo) | **No** — copied verbatim |
| **L2** | Ecosystem / OS extension | Per-repo | Yes — freely edited |

### L1 — Secrets baseline (org-managed, verbatim, required)

- The canonical source is [`/.gitignore`](../.gitignore) in this repo. It is
primarily **secrets-focused** and language-agnostic: the dotenv family, cloud-provider
credential files, Kubernetes / Helm secrets, SSH/TLS/GPG key material,
Terraform/IaC state and `*.tfvars`, secret-manager local caches (sops, age,
vault, doppler, 1password, infisical), database dumps and DB client dotfiles,
package-registry credential dotfiles (`.npmrc`, `.pypirc`,
`.cargo/credentials`, etc.), cloud CLI session caches, IDE files known to
cache credentials (JetBrains `workspace.xml`, VS Code `sftp.json`, Cursor
`mcp.json`), and modern AI/LLM tooling config files. It also includes
standard agent worktrees and CI tool artifacts per organization coding policy.
- Every repo MUST copy this block **verbatim**. Do not edit, re-order, or
remove entries inside it. Changes to the baseline are made **only** in this
repo and propagated to child repos.

### L2 — Ecosystem / OS extension (per-repo, appended below the block)

- The baseline covers **secrets and standard agent/CI paths**. Each repo MUST append its own
language-, framework-, and OS-specific entries (`node_modules/`, `target/`,
`__pycache__/`, `.DS_Store`, etc.).
- Source these from the matching template at
[github/gitignore](https://github.com/github/gitignore).
- L2 entries live **below the END marker** (see [Managed-block markers](#managed-block-markers))
and are free to edit without coordination.

## Managed-block markers

So the L1 block can be identified mechanically (for drift detection and
automated updates), it is wrapped in canonical markers in `/.gitignore`:

```gitignore
# >>> BEGIN petry-projects secrets baseline (managed by .github — do not edit) >>>
... the secrets baseline ...
# <<< END petry-projects secrets baseline <<<
```

- Everything **between** the markers is the L1 block — org-managed, byte-for-byte
identical across repos.
- Everything **below** the END marker is L2 — per-repo, freely edited.
- Nothing goes **above** the BEGIN marker.

## Negation discipline

Several baseline patterns include `!` negations that re-allow legitimate files
(e.g. `!.env.example`, `!*.crt`, `!*.pub`, `!*.enc.yaml`). These rules MUST be
preserved:

- **Keep negations immediately after the broad pattern they carve out of.**
Git evaluates rules top-to-bottom; a later ignore can re-hide a
previously-negated file.
- **L2 additions MUST NOT re-ignore a file the L1 block negates.** If a repo
re-adds a broad pattern in L2 (e.g. `*.pem`), it silently re-hides files the
baseline intentionally re-allowed.
- **Always negate by specific file path, never by directory.** A negation
inside an already-ignored directory does **not** re-include the file. To keep
a single fixture, negate the exact file (`!test/fixtures/dev-cert.pem`), not
its parent directory.

## Compliance check

The weekly audit ([`compliance-audit.sh`](../scripts/compliance-audit.sh), via
`pp_check_gitignore_secrets_block` in
[`scripts/lib/push-protection.sh`](../scripts/lib/push-protection.sh)) verifies
that a repo's `.gitignore` contains at least the baseline anchors `.env`,
`*.pem`, and `*.key` (negation lines starting with `!` do not satisfy a
requirement). Repos that copy the L1 block verbatim satisfy this automatically.
A missing file or missing anchor is reported as a `gitignore_secrets_block`
warning.

## Application to a repository

1. Copy the L1 block from [`/.gitignore`](../.gitignore) verbatim, **including
the BEGIN/END markers**, to the top of the repo's `.gitignore`.
2. Append L2 entries below the END marker, using the matching
[github/gitignore](https://github.com/github/gitignore) template.
3. Do not edit inside the markers and do not re-ignore any negated path.

## Related standards

- [`push-protection.md`](push-protection.md) — the secret-prevention program
this baseline is the first layer of.
31 changes: 5 additions & 26 deletions standards/push-protection.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,32 +316,10 @@ for a PR to merge.

### Required gitignore entries

Every repository MUST start its `.gitignore` from the org baseline at
[`/.gitignore`](../.gitignore) in this repo. The baseline is **secrets-only**
and language-agnostic — it covers the dotenv family, cloud-provider credential
files, Kubernetes / Helm secrets, SSH/TLS/GPG key material, Terraform/IaC
state and `*.tfvars`, secret-manager local caches (sops, age, vault, doppler,
1password, infisical), database dumps and DB client dotfiles, package-registry
credential dotfiles (`.npmrc`, `.pypirc`, `.cargo/credentials`, etc.), cloud
CLI session caches, IDE files known to cache credentials (JetBrains
`workspace.xml`, VS Code `sftp.json`, Cursor `mcp.json`), and modern AI/LLM
tooling config files.

> **Per-repo overrides are expected.** The baseline covers secrets only.
> Each repo MUST append its own language-specific entries (`node_modules/`,
> `target/`, `__pycache__/`, etc.) and OS cruft. Use the matching template
> from [github/gitignore](https://github.com/github/gitignore) and append
> below the baseline section.
>
> **Negation rules.** Several baseline patterns include `!` negations that
> re-allow legitimate files (e.g. `!.env.example`, `!*.crt`). Per-repo
> additions MUST NOT re-ignore those files. Always negate by **specific
> file path**, never by directory — a negation inside an ignored directory
> does not re-include the file.

The minimum compliance audit check is that the file contains at least
`.env`, `*.pem`, `*.key`, and a `secrets`-style entry. Repos that copy the
org baseline verbatim satisfy this automatically.
The `.gitignore` secrets baseline is codified in its own standard. See
[`gitignore-standard.md`](gitignore-standard.md) for the two-layer (L1
secrets baseline / L2 per-repo) model, the managed-block markers, the
negation-discipline rules, and the `gitignore_secrets_block` compliance check.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

### Writing tests and fixtures

Expand Down Expand Up @@ -494,6 +472,7 @@ audit token the visibility it needs — both steps may be needed.

## Related Standards

- [`gitignore-standard.md`](gitignore-standard.md) — the secrets-baseline `.gitignore` (L1/L2 model, managed-block markers, negation rules) that is this program's first layer
- [`advanced-security.md`](advanced-security.md) — org-wide GHAS enablement (the code security configuration that turns push protection on), licensing model, and push-protection live-fire verification
- [`github-settings.md`](github-settings.md) — repo settings, rulesets, org secrets
- [`agent-standards.md`](agent-standards.md) — AgentShield scanner and agent-config hygiene
Expand Down
Loading