feat: 'file' external type — whole-file sync for .secrets-files (EGB-652)

Built for the Beacon Android upload keystore: binary files outside the
project root can now ride the encrypted store.

- manifest: 'file <path>' (no keys; keys present = rejected loudly)
- push: encrypts the file verbatim (age is binary-safe)
- pull: restores next to target (atomic same-fs mv), mode 600, TOCTOU
  symlink recheck, divergent existing target backed up to .secrets-bak
- _validate_external_target_path parameterized by type (basename
  restriction stays gradle-properties-only; $HOME/../symlink rails apply
  to both)
- README/help/CLAUDE docs + 7 bats tests (133/133 pass)
This commit is contained in:
Brian Majewski 2026-06-07 06:43:45 -07:00
parent ab45c4c94b
commit e0474f3ce9
5 changed files with 226 additions and 40 deletions

View file

@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to a four-digit MAJOR.MINOR.PATCH.MICRO version scheme.
## [0.3.0.0] - 2026-06-07
### Added
- **`file` external type (EGB-652)** — `.secrets-files` can now sync whole
files outside the project root (binary-safe; built for the Beacon Android
upload keystore): `file ~/keystores/beacon-upload.keystore`. Push encrypts
the file verbatim into `<project>/external/`; pull restores it with mode
600, backing up a divergent existing target to `<name>.secrets-bak`. Same
path safety rails as `gradle-properties` (inside `$HOME`, no `..`, no
symlinks) minus the basename restriction. 7 new bats tests.
## [0.2.1.0] - 2026-06-05
### Fixed