Skip to content

Releases: heyvaldemar/sops-env-git

Release list

v1.1.0

Choose a tag to compare

@heyvaldemar heyvaldemar released this 14 Sep 16:45

Every content pattern in this hook looks for the shape of a credential in text. A PKCS#12 keystore is a binary blob. Traefik's acme.json holds its ACME account private key as base64 inside JSON. Neither of them looks like anything.

On the machine these rules come from, an acme.json went past a content scan in a commit where the same scan correctly rejected an ordinary DB_PASSWORD= line. The key was in the commit, the scanner had nothing to match, and the name on the file was the only warning that existed.

So acme.json, *.p12, *.pfx, *.jks, *.keystore, *.kdbx, *.key and *.ppk are now refused by name, whatever is inside them.

The list stops at credential containers on purpose. *.db and *.sqlite are secrets on a configuration host and ordinary fixtures in a normal repository, and a rule that fires on both is a rule somebody switches off — which is the history recorded at the top of the hook itself. The README says how to add them to a copy that needs them.

Thirteen more assertions, in both directions: each container shape is refused, and prose that merely names one is not. The rules match an extension rather than a substring, so docs/p12-notes.md and docs/keystore.md still commit. A hook that rejects its own documentation is a hook somebody uninstalls. Thirty-two assertions in all.

Upgrading: copy the hook again — install -m 755 hooks/pre-commit .git/hooks/pre-commit. Nothing else changed.

v1.0.0

Choose a tag to compare

@heyvaldemar heyvaldemar released this 05 Sep 05:22

Added

  • A sync that compares values, not bytes. sops drops blank lines, so a
    byte-for-byte round trip reports every file as differing forever, and an
    alarm that always fires is one nobody reads. --check reports drift by
    variable name and never prints a value.
  • Every call passes --input-type dotenv --output-type dotenv. sops picks
    its parser from the extension, does not know .sops, falls back to JSON and
    dies on the first comment line.
  • A pre-commit hook that rejects by filename before reading a byte, then by
    a narrow set of credential shapes. A .gitignore with a negation beside an
    exclusion is exactly where git add -f slips a plaintext file through, and a
    filename cannot be argued with.
  • Nineteen scenarios for the hook, in both directions. Twelve real
    credential shapes it must reject, seven benign ones it must accept —
    including a sudoers NOPASSWD line and an ordinary https URL, which are the
    false positives that got the previous version widened until it caught
    nothing.
  • Eight scenarios for the sync, against real sops and age.

Notes

  • Comments are not encrypted, on purpose: it is what makes a diff readable. It
    also means a token pasted into one goes to the remote in the clear, so the
    hook scans comments too.
  • Each machine needs its own key. One key across two hosts means compromising
    either opens the secrets of both.

Found while writing the tests

  • A pattern beginning with a dash was never matched. grep -E "$p" takes
    -----BEGIN ... PRIVATE KEY----- for an option. It needs -e, and without
    it the rule was invisible in a green run.
  • The token length rule was too strict to fire on anything but an exact
    length.
  • GitHub's own push protection refused the first push, because a suite that
    tests a secret detector necessarily contains strings shaped exactly like
    secrets. The fixtures are now assembled at runtime from pieces: the hook
    still receives the complete credential and still has to catch it, and the
    repository contains no literal that looks like one. Allowlisting them would
    have been one more exception in a project whose argument is that exceptions
    are where detectors go to die.
  • The drift report named no keys on busybox. It parsed diff output, whose
    format varies between implementations; it now compares key by key and cannot
    print an empty list while looking like it worked.