himitsubako 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. himitsubako-0.3.1/.github/workflows/ci.yml +130 -0
  2. himitsubako-0.3.1/.github/workflows/release.yml +210 -0
  3. himitsubako-0.3.1/.gitignore +56 -0
  4. himitsubako-0.3.1/CHANGELOG.md +389 -0
  5. himitsubako-0.3.1/CONTRIBUTING.md +120 -0
  6. himitsubako-0.3.1/LICENSE +21 -0
  7. himitsubako-0.3.1/PKG-INFO +231 -0
  8. himitsubako-0.3.1/README.md +179 -0
  9. himitsubako-0.3.1/SECURITY.md +70 -0
  10. himitsubako-0.3.1/docs/backends/bitwarden-cli.md +98 -0
  11. himitsubako-0.3.1/docs/backends/env.md +85 -0
  12. himitsubako-0.3.1/docs/backends/keychain.md +69 -0
  13. himitsubako-0.3.1/docs/backends/sops.md +94 -0
  14. himitsubako-0.3.1/docs/changelog.md +3 -0
  15. himitsubako-0.3.1/docs/cli-reference.md +278 -0
  16. himitsubako-0.3.1/docs/configuration.md +148 -0
  17. himitsubako-0.3.1/docs/getting-started.md +179 -0
  18. himitsubako-0.3.1/docs/index.md +47 -0
  19. himitsubako-0.3.1/docs/integrations/direnv.md +78 -0
  20. himitsubako-0.3.1/docs/integrations/pydantic-settings.md +122 -0
  21. himitsubako-0.3.1/docs/releases/v0.1.0.md +86 -0
  22. himitsubako-0.3.1/docs/releases/v0.2.0.md +211 -0
  23. himitsubako-0.3.1/docs/security.md +80 -0
  24. himitsubako-0.3.1/docs/stories/HMB-S001-project-scaffolding.md +33 -0
  25. himitsubako-0.3.1/docs/stories/HMB-S002-sops-age-backend.md +38 -0
  26. himitsubako-0.3.1/docs/stories/HMB-S003-hmb-init.md +40 -0
  27. himitsubako-0.3.1/docs/stories/HMB-S004-cli-get-set-list.md +40 -0
  28. himitsubako-0.3.1/docs/stories/HMB-S005-rotate-key.md +39 -0
  29. himitsubako-0.3.1/docs/stories/HMB-S006-python-api.md +41 -0
  30. himitsubako-0.3.1/docs/stories/HMB-S007-env-backend.md +37 -0
  31. himitsubako-0.3.1/docs/stories/HMB-S008-keychain-backend.md +39 -0
  32. himitsubako-0.3.1/docs/stories/HMB-S009-bitwarden-cli-backend.md +39 -0
  33. himitsubako-0.3.1/docs/stories/HMB-S010-direnv-helper.md +38 -0
  34. himitsubako-0.3.1/docs/stories/HMB-S011-pydantic-settings-source.md +38 -0
  35. himitsubako-0.3.1/docs/stories/HMB-S012-per-credential-routing.md +49 -0
  36. himitsubako-0.3.1/docs/stories/HMB-S013-integration-tests.md +41 -0
  37. himitsubako-0.3.1/docs/stories/HMB-S014-ci-pipeline.md +39 -0
  38. himitsubako-0.3.1/docs/stories/HMB-S015-documentation-site.md +41 -0
  39. himitsubako-0.3.1/docs/stories/HMB-S016-pypi-publish-prep.md +40 -0
  40. himitsubako-0.3.1/docs/why-not.md +60 -0
  41. himitsubako-0.3.1/mkdocs.yml +86 -0
  42. himitsubako-0.3.1/pyproject.toml +129 -0
  43. himitsubako-0.3.1/src/himitsubako/__init__.py +9 -0
  44. himitsubako-0.3.1/src/himitsubako/api.py +80 -0
  45. himitsubako-0.3.1/src/himitsubako/backends/__init__.py +3 -0
  46. himitsubako-0.3.1/src/himitsubako/backends/bitwarden.py +251 -0
  47. himitsubako-0.3.1/src/himitsubako/backends/env.py +68 -0
  48. himitsubako-0.3.1/src/himitsubako/backends/keychain.py +128 -0
  49. himitsubako-0.3.1/src/himitsubako/backends/protocol.py +35 -0
  50. himitsubako-0.3.1/src/himitsubako/backends/sops.py +179 -0
  51. himitsubako-0.3.1/src/himitsubako/cli/__init__.py +32 -0
  52. himitsubako-0.3.1/src/himitsubako/cli/init.py +170 -0
  53. himitsubako-0.3.1/src/himitsubako/cli/rotate.py +100 -0
  54. himitsubako-0.3.1/src/himitsubako/cli/secrets.py +235 -0
  55. himitsubako-0.3.1/src/himitsubako/cli/status.py +251 -0
  56. himitsubako-0.3.1/src/himitsubako/config.py +140 -0
  57. himitsubako-0.3.1/src/himitsubako/direnv.py +97 -0
  58. himitsubako-0.3.1/src/himitsubako/errors.py +33 -0
  59. himitsubako-0.3.1/src/himitsubako/pydantic.py +114 -0
  60. himitsubako-0.3.1/src/himitsubako/router.py +134 -0
  61. himitsubako-0.3.1/tests/__init__.py +0 -0
  62. himitsubako-0.3.1/tests/conftest.py +35 -0
  63. himitsubako-0.3.1/tests/integration/__init__.py +0 -0
  64. himitsubako-0.3.1/tests/integration/conftest.py +182 -0
  65. himitsubako-0.3.1/tests/integration/test_bitwarden_real.py +132 -0
  66. himitsubako-0.3.1/tests/integration/test_cli_e2e.py +123 -0
  67. himitsubako-0.3.1/tests/integration/test_direnv_real.py +212 -0
  68. himitsubako-0.3.1/tests/integration/test_env_roundtrip.py +99 -0
  69. himitsubako-0.3.1/tests/integration/test_keychain_real.py +131 -0
  70. himitsubako-0.3.1/tests/integration/test_router_real.py +109 -0
  71. himitsubako-0.3.1/tests/integration/test_sops_roundtrip.py +183 -0
  72. himitsubako-0.3.1/tests/test_api.py +111 -0
  73. himitsubako-0.3.1/tests/test_bitwarden_backend.py +270 -0
  74. himitsubako-0.3.1/tests/test_cli_init.py +128 -0
  75. himitsubako-0.3.1/tests/test_cli_rotate.py +80 -0
  76. himitsubako-0.3.1/tests/test_cli_secrets.py +414 -0
  77. himitsubako-0.3.1/tests/test_cli_status.py +481 -0
  78. himitsubako-0.3.1/tests/test_config.py +106 -0
  79. himitsubako-0.3.1/tests/test_direnv.py +112 -0
  80. himitsubako-0.3.1/tests/test_env_backend.py +149 -0
  81. himitsubako-0.3.1/tests/test_errors.py +48 -0
  82. himitsubako-0.3.1/tests/test_init.py +23 -0
  83. himitsubako-0.3.1/tests/test_keychain_backend.py +204 -0
  84. himitsubako-0.3.1/tests/test_protocol.py +51 -0
  85. himitsubako-0.3.1/tests/test_pydantic_source.py +93 -0
  86. himitsubako-0.3.1/tests/test_router.py +220 -0
  87. himitsubako-0.3.1/tests/test_sops_backend.py +410 -0
  88. himitsubako-0.3.1/uv.lock +1332 -0
@@ -0,0 +1,130 @@
1
+ # HMB-S014: Continuous integration pipeline.
2
+ #
3
+ # Supply-chain notes
4
+ # ------------------
5
+ # - Every `uses:` reference is pinned to a commit SHA, not a tag
6
+ # (Obsidian/code/supply-chain-protection.md). Tag pointers below
7
+ # the SHA are documentation only and are the version at the time of
8
+ # pinning; the SHA is what GitHub resolves and the version can drift.
9
+ # - `sops` and `age` are installed from upstream GitHub releases and
10
+ # verified by SHA256, not `apt-get install`. The apt version in
11
+ # Ubuntu LTS lags the upstream release train by multiple versions
12
+ # and would not carry the v3.8+ `--filename-override` flag that
13
+ # `SopsBackend._encrypt` depends on (see HMB-S013).
14
+ #
15
+ # Action pins (tag at pinning time → commit SHA)
16
+ # actions/checkout v4.3.0 08eba0b27e820071cde6df949e0beb9ba4906955
17
+ # astral-sh/setup-uv v5.4.1 0c5e2b8115b80b4c7c5ddf6ffdd634974642d182
18
+ # actions/upload-artifact v4.6.2 ea165f8d65b6e75b540449e92b4886f43607fa02
19
+ #
20
+ # Binary pins (version → linux amd64 SHA256)
21
+ # sops v3.12.2 14e2e1ba3bef31e74b70cf0b674f6443c80f6c5f3df15d05ffc57c34851b4998
22
+ # age v1.3.1 bdc69c09cbdd6cf8b1f333d372a1f58247b3a33146406333e30c0f26e8f51377
23
+ #
24
+ # To bump a pin, edit both the SHA (line that GitHub actually reads)
25
+ # and the comment (human-readable version), re-resolve via
26
+ # `git ls-remote` / release checksums, and commit in a dedicated PR.
27
+
28
+ name: ci
29
+
30
+ on:
31
+ push:
32
+ branches: [main]
33
+ pull_request:
34
+
35
+ permissions:
36
+ contents: read
37
+
38
+ concurrency:
39
+ group: ci-${{ github.workflow }}-${{ github.ref }}
40
+ cancel-in-progress: true
41
+
42
+ env:
43
+ SOPS_VERSION: v3.12.2
44
+ SOPS_LINUX_AMD64_SHA256: 14e2e1ba3bef31e74b70cf0b674f6443c80f6c5f3df15d05ffc57c34851b4998
45
+ AGE_VERSION: v1.3.1
46
+ AGE_LINUX_AMD64_SHA256: bdc69c09cbdd6cf8b1f333d372a1f58247b3a33146406333e30c0f26e8f51377
47
+
48
+ jobs:
49
+ test:
50
+ name: test (py${{ matrix.python-version }})
51
+ runs-on: ubuntu-latest
52
+ strategy:
53
+ fail-fast: false
54
+ matrix:
55
+ python-version: ["3.12", "3.13"]
56
+
57
+ steps:
58
+ - name: Checkout
59
+ uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
60
+ with:
61
+ fetch-depth: 0
62
+
63
+ - name: Install uv
64
+ uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1
65
+ with:
66
+ python-version: ${{ matrix.python-version }}
67
+ enable-cache: true
68
+
69
+ - name: Install sops (pinned + SHA256 verified)
70
+ run: |
71
+ set -euo pipefail
72
+ mkdir -p "$HOME/.local/bin"
73
+ url="https://github.com/getsops/sops/releases/download/${SOPS_VERSION}/sops-${SOPS_VERSION}.linux.amd64"
74
+ curl -fsSL -o sops-bin "$url"
75
+ echo "${SOPS_LINUX_AMD64_SHA256} sops-bin" | sha256sum -c -
76
+ install -m 0755 sops-bin "$HOME/.local/bin/sops"
77
+ rm -f sops-bin
78
+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
79
+ "$HOME/.local/bin/sops" --version
80
+
81
+ - name: Install age (pinned + SHA256 verified)
82
+ run: |
83
+ set -euo pipefail
84
+ mkdir -p "$HOME/.local/bin"
85
+ url="https://github.com/FiloSottile/age/releases/download/${AGE_VERSION}/age-${AGE_VERSION}-linux-amd64.tar.gz"
86
+ curl -fsSL -o age.tar.gz "$url"
87
+ echo "${AGE_LINUX_AMD64_SHA256} age.tar.gz" | sha256sum -c -
88
+ tar -xzf age.tar.gz
89
+ install -m 0755 age/age "$HOME/.local/bin/age"
90
+ install -m 0755 age/age-keygen "$HOME/.local/bin/age-keygen"
91
+ rm -rf age age.tar.gz
92
+ "$HOME/.local/bin/age" --version
93
+ "$HOME/.local/bin/age-keygen" --help >/dev/null 2>&1 || true
94
+
95
+ - name: Install project (all extras + dev)
96
+ run: uv sync --all-extras --dev
97
+
98
+ - name: Ruff lint
99
+ run: uv run ruff check src tests
100
+
101
+ - name: Ruff format check
102
+ run: uv run ruff format --check src tests
103
+
104
+ - name: mypy
105
+ run: uv run mypy src
106
+
107
+ - name: Unit tests + coverage gate
108
+ run: >-
109
+ uv run pytest
110
+ --override-ini="addopts=-v --tb=short"
111
+ -m "not integration"
112
+ --cov=src/himitsubako
113
+ --cov-report=xml
114
+ --cov-report=term-missing
115
+ --cov-fail-under=80
116
+
117
+ - name: Integration tests (S013 subset — sops + env)
118
+ run: >-
119
+ uv run pytest tests/integration/
120
+ --override-ini="addopts=-v --tb=short"
121
+ -m "integration and not macos and not bitwarden and not direnv"
122
+
123
+ - name: Upload coverage XML
124
+ if: ${{ always() }}
125
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
126
+ with:
127
+ name: coverage-xml-py${{ matrix.python-version }}
128
+ path: coverage.xml
129
+ if-no-files-found: warn
130
+ retention-days: 14
@@ -0,0 +1,210 @@
1
+ # HMB-S016: Release workflow — publish to PyPI via Trusted Publishers (OIDC).
2
+ #
3
+ # Supply-chain notes
4
+ # ------------------
5
+ # - Same SHA-pinning policy as the CI workflow. Every `uses:` reference
6
+ # is pinned to a commit SHA, not a tag (supply-chain policy per
7
+ # Obsidian/code/supply-chain-protection.md). Tag pointers below the
8
+ # SHA are documentation only.
9
+ # - `sops` and `age` are installed from upstream releases with SHA256
10
+ # verification, identical to the CI workflow. The release build only
11
+ # needs them for the integration test step; publish itself does not.
12
+ # - **No long-lived PyPI API token.** Production publish uses Trusted
13
+ # Publishers (OIDC) bound to this repository + this workflow file +
14
+ # the `pypi-release` environment. The repository owner must configure
15
+ # the binding on pypi.org before the first release tag runs.
16
+ # - The `pypi-release` environment has a required-reviewer gate so an
17
+ # accidental tag push cannot auto-publish. A human must approve the
18
+ # job before the publish step runs.
19
+ #
20
+ # Action pins (tag at pinning time → commit SHA)
21
+ # actions/checkout v4.3.0 08eba0b27e820071cde6df949e0beb9ba4906955
22
+ # astral-sh/setup-uv v5.4.1 0c5e2b8115b80b4c7c5ddf6ffdd634974642d182
23
+ # actions/upload-artifact v4.6.2 ea165f8d65b6e75b540449e92b4886f43607fa02
24
+ # actions/download-artifact v4.3.0 d3f86a106a0bac45b974a628896c90dbdf5c8093
25
+ #
26
+ # Docker container action exception:
27
+ # pypa/gh-action-pypi-publish is a Docker container action whose
28
+ # registry image is tagged by release version, not by commit SHA.
29
+ # Pinning to a commit SHA causes the action wrapper to attempt
30
+ # `docker pull ghcr.io/pypa/gh-action-pypi-publish:<sha>`, which
31
+ # fails with `manifest unknown` because no SHA-tagged image
32
+ # exists. PyPA's published guidance for this action is to pin to
33
+ # a specific version tag instead. We pin to v1.13.0 (released
34
+ # 2025-09-04, well past the 7-day quarantine window) and accept
35
+ # the slightly weaker supply-chain posture for this one action.
36
+ # PyPA does not move version tags, so the trust delta vs SHA
37
+ # pinning is small in practice.
38
+ #
39
+ # Binary pins — same as ci.yml:
40
+ # sops v3.12.2 14e2e1ba3bef31e74b70cf0b674f6443c80f6c5f3df15d05ffc57c34851b4998
41
+ # age v1.3.1 bdc69c09cbdd6cf8b1f333d372a1f58247b3a33146406333e30c0f26e8f51377
42
+
43
+ name: release
44
+
45
+ on:
46
+ push:
47
+ tags:
48
+ # Final v*.*.* tags only. Pre-release tags (v*-rc*, v*-beta*)
49
+ # are intentionally excluded until a decision is made on whether
50
+ # to publish them.
51
+ - 'v[0-9]+.[0-9]+.[0-9]+'
52
+
53
+ permissions:
54
+ contents: read
55
+
56
+ concurrency:
57
+ group: release-${{ github.ref }}
58
+ cancel-in-progress: false
59
+
60
+ env:
61
+ SOPS_VERSION: v3.12.2
62
+ SOPS_LINUX_AMD64_SHA256: 14e2e1ba3bef31e74b70cf0b674f6443c80f6c5f3df15d05ffc57c34851b4998
63
+ AGE_VERSION: v1.3.1
64
+ AGE_LINUX_AMD64_SHA256: bdc69c09cbdd6cf8b1f333d372a1f58247b3a33146406333e30c0f26e8f51377
65
+
66
+ jobs:
67
+ verify:
68
+ name: verify (pre-publish CI gate)
69
+ runs-on: ubuntu-latest
70
+ steps:
71
+ - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
72
+ with:
73
+ fetch-depth: 0
74
+
75
+ - name: Install uv
76
+ uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1
77
+ with:
78
+ python-version: "3.13"
79
+ enable-cache: true
80
+
81
+ - name: Install sops (pinned + SHA256 verified)
82
+ run: |
83
+ set -euo pipefail
84
+ mkdir -p "$HOME/.local/bin"
85
+ url="https://github.com/getsops/sops/releases/download/${SOPS_VERSION}/sops-${SOPS_VERSION}.linux.amd64"
86
+ curl -fsSL -o sops-bin "$url"
87
+ echo "${SOPS_LINUX_AMD64_SHA256} sops-bin" | sha256sum -c -
88
+ install -m 0755 sops-bin "$HOME/.local/bin/sops"
89
+ rm -f sops-bin
90
+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
91
+
92
+ - name: Install age (pinned + SHA256 verified)
93
+ run: |
94
+ set -euo pipefail
95
+ mkdir -p "$HOME/.local/bin"
96
+ url="https://github.com/FiloSottile/age/releases/download/${AGE_VERSION}/age-${AGE_VERSION}-linux-amd64.tar.gz"
97
+ curl -fsSL -o age.tar.gz "$url"
98
+ echo "${AGE_LINUX_AMD64_SHA256} age.tar.gz" | sha256sum -c -
99
+ tar -xzf age.tar.gz
100
+ install -m 0755 age/age "$HOME/.local/bin/age"
101
+ install -m 0755 age/age-keygen "$HOME/.local/bin/age-keygen"
102
+ rm -rf age age.tar.gz
103
+
104
+ - name: Install project (all extras + dev)
105
+ run: uv sync --all-extras --dev
106
+
107
+ - name: Ruff lint
108
+ run: uv run ruff check src tests
109
+
110
+ - name: Ruff format check
111
+ run: uv run ruff format --check src tests
112
+
113
+ - name: mypy
114
+ run: uv run mypy src
115
+
116
+ - name: Unit tests + coverage gate
117
+ run: >-
118
+ uv run pytest
119
+ --override-ini="addopts=-v --tb=short"
120
+ -m "not integration"
121
+ --cov=src/himitsubako
122
+ --cov-report=term-missing
123
+ --cov-fail-under=80
124
+
125
+ - name: Integration tests (S013 subset)
126
+ run: >-
127
+ uv run pytest tests/integration/
128
+ --override-ini="addopts=-v --tb=short"
129
+ -m "integration and not macos and not bitwarden and not direnv"
130
+
131
+ build:
132
+ name: build (wheel + sdist)
133
+ needs: verify
134
+ runs-on: ubuntu-latest
135
+ steps:
136
+ - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
137
+ with:
138
+ fetch-depth: 0
139
+
140
+ - name: Install uv
141
+ uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1
142
+ with:
143
+ python-version: "3.13"
144
+ enable-cache: true
145
+
146
+ - name: Install project with publish extras
147
+ run: uv sync --all-extras --dev
148
+
149
+ - name: Verify tag matches pyproject.toml version
150
+ run: |
151
+ set -euo pipefail
152
+ tag="${GITHUB_REF_NAME}"
153
+ version="${tag#v}"
154
+ pyproject_version=$(uv run python -c "import tomllib; print(tomllib.loads(open('pyproject.toml','rb').read().decode())['project']['version'])")
155
+ init_version=$(uv run python -c "from himitsubako import __version__; print(__version__)")
156
+ if [[ "$pyproject_version" != "$version" ]]; then
157
+ echo "ERROR: tag $tag implies version $version but pyproject.toml has $pyproject_version" >&2
158
+ exit 1
159
+ fi
160
+ if [[ "$init_version" != "$version" ]]; then
161
+ echo "ERROR: tag $tag implies version $version but himitsubako.__version__ is $init_version" >&2
162
+ exit 1
163
+ fi
164
+ echo "Tag, pyproject.toml, and __version__ all agree on $version."
165
+
166
+ - name: Build sdist and wheel
167
+ run: uv run python -m build
168
+
169
+ - name: Twine check
170
+ run: uv run twine check dist/*
171
+
172
+ - name: Upload dist artifacts
173
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
174
+ with:
175
+ name: dist
176
+ path: dist/
177
+ if-no-files-found: error
178
+ retention-days: 14
179
+
180
+ publish:
181
+ name: publish to PyPI (Trusted Publishers OIDC)
182
+ needs: build
183
+ runs-on: ubuntu-latest
184
+ # Required-reviewer gate: the pypi-release environment must be
185
+ # configured on the repository (Settings → Environments) with at
186
+ # least one required reviewer (the maintainer). That reviewer is
187
+ # the human approval on every release.
188
+ environment:
189
+ name: pypi-release
190
+ url: https://pypi.org/project/himitsubako/
191
+ permissions:
192
+ # Needed for Trusted Publishers OIDC.
193
+ id-token: write
194
+ contents: read
195
+ steps:
196
+ - name: Download dist artifact
197
+ uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
198
+ with:
199
+ name: dist
200
+ path: dist/
201
+
202
+ - name: Publish to PyPI via Trusted Publishers
203
+ # Tag-pinned (NOT SHA-pinned) — see the "Docker container action
204
+ # exception" note in the header. v1.13.0 release is 2025-09-04.
205
+ uses: pypa/gh-action-pypi-publish@v1.13.0
206
+ with:
207
+ packages-dir: dist/
208
+ # No `password:` — OIDC Trusted Publisher binding on PyPI
209
+ # provides the short-lived token automatically.
210
+ verbose: true
@@ -0,0 +1,56 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ *.egg
7
+ dist/
8
+ build/
9
+ .eggs/
10
+
11
+ # Virtual environments
12
+ .venv/
13
+ venv/
14
+ env/
15
+ ENV/
16
+
17
+ # Testing
18
+ .pytest_cache/
19
+ .coverage
20
+ htmlcov/
21
+ .tox/
22
+ coverage.xml
23
+ *.cover
24
+
25
+ # Type checking
26
+ .mypy_cache/
27
+ .ruff_cache/
28
+
29
+ # IDE
30
+ .vscode/
31
+ .idea/
32
+ *.swp
33
+ *.swo
34
+ *~
35
+
36
+ # macOS
37
+ .DS_Store
38
+
39
+ # Secrets — belt and suspenders
40
+ # himitsubako's own test/example files should always be encrypted before commit,
41
+ # but never commit plaintext decrypted files even by accident
42
+ *.dec.yaml
43
+ *.dec.yml
44
+ *.dec.json
45
+ *.plaintext
46
+ secrets.yaml
47
+ .env
48
+ .env.local
49
+ .envrc.local
50
+
51
+ # Docs site
52
+ site/
53
+
54
+ # UV lockfile — commit it
55
+ # (uncomment next line if you want to gitignore it instead)
56
+ # uv.lock