promptlatch 0.2.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 (107) hide show
  1. promptlatch-0.2.1/.dockerignore +15 -0
  2. promptlatch-0.2.1/.github/dependabot.yml +44 -0
  3. promptlatch-0.2.1/.github/workflows/ci.yml +62 -0
  4. promptlatch-0.2.1/.github/workflows/codeql.yml +32 -0
  5. promptlatch-0.2.1/.github/workflows/dependency-review.yml +21 -0
  6. promptlatch-0.2.1/.github/workflows/release.yml +168 -0
  7. promptlatch-0.2.1/.gitignore +16 -0
  8. promptlatch-0.2.1/AGENTS.md +15 -0
  9. promptlatch-0.2.1/AGENTS_DEPLOY.md +48 -0
  10. promptlatch-0.2.1/AGENTS_MONITOR.md +39 -0
  11. promptlatch-0.2.1/AGENTS_TESTING.md +31 -0
  12. promptlatch-0.2.1/CONTRIBUTING.md +70 -0
  13. promptlatch-0.2.1/Dockerfile +20 -0
  14. promptlatch-0.2.1/LICENSE +21 -0
  15. promptlatch-0.2.1/PKG-INFO +767 -0
  16. promptlatch-0.2.1/PROMPT.md +161 -0
  17. promptlatch-0.2.1/README.md +729 -0
  18. promptlatch-0.2.1/SECURITY.md +40 -0
  19. promptlatch-0.2.1/SECURITY_AUDIT.md +32 -0
  20. promptlatch-0.2.1/charts/promptlatch/Chart.yaml +7 -0
  21. promptlatch-0.2.1/charts/promptlatch/templates/_helpers.tpl +53 -0
  22. promptlatch-0.2.1/charts/promptlatch/templates/deployment.yaml +69 -0
  23. promptlatch-0.2.1/charts/promptlatch/templates/secret.yaml +16 -0
  24. promptlatch-0.2.1/charts/promptlatch/templates/service.yaml +15 -0
  25. promptlatch-0.2.1/charts/promptlatch/values.yaml +51 -0
  26. promptlatch-0.2.1/docker-compose.yml +8 -0
  27. promptlatch-0.2.1/examples/codex-openrouter-promptlatch.config.toml +12 -0
  28. promptlatch-0.2.1/examples/opencode-openrouter-promptlatch.json +22 -0
  29. promptlatch-0.2.1/examples/promptlatch-openrouter.config.yaml +33 -0
  30. promptlatch-0.2.1/pyproject.toml +72 -0
  31. promptlatch-0.2.1/scripts/audit_secrets.py +181 -0
  32. promptlatch-0.2.1/scripts/check_helm.py +96 -0
  33. promptlatch-0.2.1/scripts/check_release.py +125 -0
  34. promptlatch-0.2.1/site/PROMPT.md +161 -0
  35. promptlatch-0.2.1/site/favicon.svg +5 -0
  36. promptlatch-0.2.1/site/hero.png +0 -0
  37. promptlatch-0.2.1/site/highlight.js +101 -0
  38. promptlatch-0.2.1/site/icons/LICENSE-lobe-icons.txt +21 -0
  39. promptlatch-0.2.1/site/icons/LICENSE-lucide.txt +43 -0
  40. promptlatch-0.2.1/site/icons/LICENSE-simple-icons.md +30 -0
  41. promptlatch-0.2.1/site/icons/NOTICE.md +13 -0
  42. promptlatch-0.2.1/site/icons/anthropic.svg +1 -0
  43. promptlatch-0.2.1/site/icons/atlassian.svg +1 -0
  44. promptlatch-0.2.1/site/icons/aws.svg +1 -0
  45. promptlatch-0.2.1/site/icons/check.svg +15 -0
  46. promptlatch-0.2.1/site/icons/cloudflare.svg +1 -0
  47. promptlatch-0.2.1/site/icons/codex.svg +1 -0
  48. promptlatch-0.2.1/site/icons/copy.svg +16 -0
  49. promptlatch-0.2.1/site/icons/deepseek.svg +1 -0
  50. promptlatch-0.2.1/site/icons/file-key-2.svg +19 -0
  51. promptlatch-0.2.1/site/icons/fireworks.svg +1 -0
  52. promptlatch-0.2.1/site/icons/gemini.svg +1 -0
  53. promptlatch-0.2.1/site/icons/github.svg +1 -0
  54. promptlatch-0.2.1/site/icons/hash.svg +18 -0
  55. promptlatch-0.2.1/site/icons/jwt.svg +1 -0
  56. promptlatch-0.2.1/site/icons/key-round.svg +16 -0
  57. promptlatch-0.2.1/site/icons/link-2.svg +17 -0
  58. promptlatch-0.2.1/site/icons/minimax.svg +1 -0
  59. promptlatch-0.2.1/site/icons/openai.svg +1 -0
  60. promptlatch-0.2.1/site/icons/openrouter.svg +1 -0
  61. promptlatch-0.2.1/site/icons/regex.svg +18 -0
  62. promptlatch-0.2.1/site/icons/stripe.svg +1 -0
  63. promptlatch-0.2.1/site/icons/xai.svg +1 -0
  64. promptlatch-0.2.1/site/icons/zai.svg +1 -0
  65. promptlatch-0.2.1/site/index.html +466 -0
  66. promptlatch-0.2.1/site/prompt.js +29 -0
  67. promptlatch-0.2.1/site/styles.css +559 -0
  68. promptlatch-0.2.1/src/promptcloak/__init__.py +40 -0
  69. promptlatch-0.2.1/src/promptcloak/asgi.py +3 -0
  70. promptlatch-0.2.1/src/promptcloak/audit.py +1 -0
  71. promptlatch-0.2.1/src/promptcloak/cli.py +3 -0
  72. promptlatch-0.2.1/src/promptcloak/compat.py +1 -0
  73. promptlatch-0.2.1/src/promptcloak/config.py +1 -0
  74. promptlatch-0.2.1/src/promptcloak/library.py +1 -0
  75. promptlatch-0.2.1/src/promptcloak/patterns.py +1 -0
  76. promptlatch-0.2.1/src/promptcloak/proxy.py +3 -0
  77. promptlatch-0.2.1/src/promptcloak/py.typed +1 -0
  78. promptlatch-0.2.1/src/promptcloak/redaction.py +1 -0
  79. promptlatch-0.2.1/src/promptcloak/security.py +1 -0
  80. promptlatch-0.2.1/src/promptcloak/version.py +3 -0
  81. promptlatch-0.2.1/src/promptlatch/__init__.py +27 -0
  82. promptlatch-0.2.1/src/promptlatch/asgi.py +3 -0
  83. promptlatch-0.2.1/src/promptlatch/audit.py +34 -0
  84. promptlatch-0.2.1/src/promptlatch/cli.py +143 -0
  85. promptlatch-0.2.1/src/promptlatch/compat.py +486 -0
  86. promptlatch-0.2.1/src/promptlatch/config.py +343 -0
  87. promptlatch-0.2.1/src/promptlatch/library.py +148 -0
  88. promptlatch-0.2.1/src/promptlatch/patterns.py +114 -0
  89. promptlatch-0.2.1/src/promptlatch/proxy.py +591 -0
  90. promptlatch-0.2.1/src/promptlatch/py.typed +1 -0
  91. promptlatch-0.2.1/src/promptlatch/redaction.py +237 -0
  92. promptlatch-0.2.1/src/promptlatch/security.py +70 -0
  93. promptlatch-0.2.1/src/promptlatch/version.py +3 -0
  94. promptlatch-0.2.1/tests/__init__.py +1 -0
  95. promptlatch-0.2.1/tests/fixtures.py +127 -0
  96. promptlatch-0.2.1/tests/test_audit.py +18 -0
  97. promptlatch-0.2.1/tests/test_cli.py +79 -0
  98. promptlatch-0.2.1/tests/test_compat.py +232 -0
  99. promptlatch-0.2.1/tests/test_config.py +131 -0
  100. promptlatch-0.2.1/tests/test_docs.py +70 -0
  101. promptlatch-0.2.1/tests/test_e2e.py +497 -0
  102. promptlatch-0.2.1/tests/test_examples.py +55 -0
  103. promptlatch-0.2.1/tests/test_library.py +119 -0
  104. promptlatch-0.2.1/tests/test_proxy.py +1271 -0
  105. promptlatch-0.2.1/tests/test_redaction.py +378 -0
  106. promptlatch-0.2.1/tests/test_security.py +58 -0
  107. promptlatch-0.2.1/uv.lock +1277 -0
@@ -0,0 +1,15 @@
1
+ .git
2
+ .venv
3
+ .pytest_cache
4
+ .ruff_cache
5
+ dist
6
+ build
7
+ *.egg-info
8
+ __pycache__
9
+ **/__pycache__/
10
+ **/*.py[cod]
11
+ node_modules
12
+ site/screenshots
13
+ *.log
14
+ .env
15
+ .env.*
@@ -0,0 +1,44 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: uv
4
+ directory: /
5
+ schedule:
6
+ interval: weekly
7
+ versioning-strategy: lockfile-only
8
+ cooldown:
9
+ default-days: 7
10
+ semver-major-days: 30
11
+ semver-minor-days: 7
12
+ semver-patch-days: 3
13
+ groups:
14
+ python-dependencies:
15
+ patterns: ["*"]
16
+ open-pull-requests-limit: 5
17
+ - package-ecosystem: github-actions
18
+ directory: /
19
+ schedule:
20
+ interval: weekly
21
+ cooldown:
22
+ default-days: 7
23
+ semver-major-days: 30
24
+ semver-minor-days: 7
25
+ semver-patch-days: 3
26
+ groups:
27
+ actions:
28
+ patterns: ["*"]
29
+ open-pull-requests-limit: 5
30
+ - package-ecosystem: docker
31
+ directory: /
32
+ schedule:
33
+ interval: weekly
34
+ cooldown:
35
+ default-days: 7
36
+ semver-major-days: 30
37
+ semver-minor-days: 7
38
+ semver-patch-days: 3
39
+ ignore:
40
+ - dependency-name: python
41
+ update-types:
42
+ - version-update:semver-major
43
+ - version-update:semver-minor
44
+ open-pull-requests-limit: 5
@@ -0,0 +1,62 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ci-${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ test:
17
+ name: test (${{ matrix.python-version }})
18
+ runs-on: ubuntu-latest
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ python-version: ["3.12", "3.13", "3.14"]
23
+ steps:
24
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
25
+ with:
26
+ fetch-depth: 0
27
+ persist-credentials: false
28
+ - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
29
+ - name: Install Python
30
+ env:
31
+ PYTHON_VERSION: ${{ matrix.python-version }}
32
+ run: uv python install "$PYTHON_VERSION"
33
+ - name: Sync environment
34
+ env:
35
+ PYTHON_VERSION: ${{ matrix.python-version }}
36
+ run: uv sync --python "$PYTHON_VERSION" --extra dev --locked
37
+ - run: uv run pytest
38
+
39
+ package:
40
+ name: package
41
+ needs: test
42
+ runs-on: ubuntu-latest
43
+ steps:
44
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
45
+ with:
46
+ fetch-depth: 0
47
+ persist-credentials: false
48
+ - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
49
+ - uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
50
+ - run: uv sync --extra dev --group audit --locked
51
+ - run: uv run scripts/check_release.py
52
+ - run: uv run scripts/audit_secrets.py
53
+ - run: uv run ruff check .
54
+ - run: uv run ruff format --check .
55
+ - run: uv run pyright src tests scripts
56
+ - run: uv run pip-audit
57
+ - run: uv build
58
+ - run: helm lint ./charts/promptlatch
59
+ - run: helm template promptlatch ./charts/promptlatch >/dev/null
60
+ - run: uv run scripts/check_helm.py
61
+ - run: docker build -t promptlatch:ci .
62
+ - run: docker run --rm --entrypoint promptlatch promptlatch:ci version
@@ -0,0 +1,32 @@
1
+ name: codeql
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ schedule:
8
+ - cron: "17 4 * * 1"
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: codeql-${{ github.workflow }}-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ analyze:
19
+ name: analyze
20
+ runs-on: ubuntu-latest
21
+ permissions:
22
+ contents: read
23
+ security-events: write # Upload CodeQL results.
24
+ steps:
25
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
26
+ with:
27
+ persist-credentials: false
28
+ - uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
29
+ with:
30
+ languages: python
31
+ build-mode: none
32
+ - uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
@@ -0,0 +1,21 @@
1
+ name: dependency-review
2
+
3
+ on:
4
+ pull_request:
5
+
6
+ permissions:
7
+ contents: read
8
+
9
+ concurrency:
10
+ group: dependency-review-${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ review:
15
+ name: review
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
19
+ with:
20
+ persist-credentials: false
21
+ - uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
@@ -0,0 +1,168 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ tag:
10
+ description: Existing release tag to publish
11
+ required: true
12
+ type: string
13
+
14
+ env:
15
+ RELEASE_TAG: ${{ inputs.tag || github.ref_name }}
16
+ IMAGE_NAME: ghcr.io/bvolpato/promptlatch
17
+
18
+ permissions:
19
+ contents: read
20
+
21
+ concurrency:
22
+ group: release-${{ inputs.tag || github.ref_name }}
23
+ cancel-in-progress: false
24
+
25
+ jobs:
26
+ build:
27
+ name: build
28
+ runs-on: ubuntu-latest
29
+ permissions:
30
+ attestations: write # Publish provenance for release artifacts.
31
+ contents: read
32
+ id-token: write # Sign provenance through GitHub OIDC.
33
+ steps:
34
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
35
+ with:
36
+ fetch-depth: 0
37
+ persist-credentials: false
38
+ ref: ${{ env.RELEASE_TAG }}
39
+ - name: Verify release tag
40
+ env:
41
+ GH_TOKEN: ${{ github.token }}
42
+ run: |
43
+ set -euo pipefail
44
+ if [ "$GITHUB_REPOSITORY" != "bvolpato/promptlatch" ]; then
45
+ echo "release must run from bvolpato/promptlatch" >&2
46
+ exit 1
47
+ fi
48
+ ref_json=$(gh api "repos/$GITHUB_REPOSITORY/git/ref/tags/$RELEASE_TAG")
49
+ if [ "$(jq -r '.object.type' <<<"$ref_json")" != "tag" ]; then
50
+ echo "release tag must be annotated and signed" >&2
51
+ exit 1
52
+ fi
53
+ tag_sha=$(jq -r '.object.sha' <<<"$ref_json")
54
+ if [ "$(gh api "repos/$GITHUB_REPOSITORY/git/tags/$tag_sha" --jq '.verification.verified')" != "true" ]; then
55
+ echo "release tag signature is not verified" >&2
56
+ exit 1
57
+ fi
58
+ git fetch --no-tags origin main:refs/remotes/origin/main
59
+ if ! git merge-base --is-ancestor "$RELEASE_TAG^{commit}" origin/main; then
60
+ echo "release tag must point to a commit on main" >&2
61
+ exit 1
62
+ fi
63
+ - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
64
+ with:
65
+ enable-cache: false
66
+ - uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
67
+ - run: uv sync --extra dev --group audit --locked
68
+ - run: uv run scripts/check_release.py --tag "$RELEASE_TAG"
69
+ - run: uv run scripts/audit_secrets.py
70
+ - run: uv run ruff check .
71
+ - run: uv run ruff format --check .
72
+ - run: uv run pyright src tests scripts
73
+ - run: uv run pip-audit
74
+ - run: uv run pytest
75
+ - run: uv build
76
+ - run: helm lint ./charts/promptlatch
77
+ - run: helm template promptlatch ./charts/promptlatch >/dev/null
78
+ - run: uv run scripts/check_helm.py
79
+ - run: helm package charts/promptlatch --destination dist
80
+ - run: cd dist && sha256sum -- ./*.whl ./*.tar.gz ./*.tgz > SHA256SUMS
81
+ - uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
82
+ with:
83
+ subject-path: dist/*
84
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
85
+ with:
86
+ name: release-dist
87
+ path: dist/*
88
+ if-no-files-found: error
89
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
90
+ with:
91
+ name: python-dist
92
+ path: |
93
+ dist/*.whl
94
+ dist/*.tar.gz
95
+ if-no-files-found: error
96
+
97
+ publish-pypi:
98
+ name: publish-pypi
99
+ needs: build
100
+ runs-on: ubuntu-latest
101
+ environment:
102
+ name: pypi
103
+ url: https://pypi.org/p/promptlatch
104
+ permissions:
105
+ id-token: write # Exchange GitHub OIDC identity for a short-lived PyPI token.
106
+ steps:
107
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
108
+ with:
109
+ name: python-dist
110
+ path: dist
111
+ - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
112
+
113
+ publish:
114
+ name: publish
115
+ needs: build
116
+ runs-on: ubuntu-latest
117
+ permissions:
118
+ contents: write # Create or repair GitHub release assets.
119
+ packages: write # Push versioned GHCR image.
120
+ steps:
121
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
122
+ with:
123
+ fetch-depth: 0
124
+ persist-credentials: false
125
+ ref: ${{ env.RELEASE_TAG }}
126
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
127
+ with:
128
+ name: release-dist
129
+ path: dist
130
+ - uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
131
+ with:
132
+ registry: ghcr.io
133
+ username: ${{ github.actor }}
134
+ password: ${{ github.token }}
135
+ - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
136
+ - uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
137
+ id: docker-meta
138
+ with:
139
+ images: ${{ env.IMAGE_NAME }}
140
+ tags: |
141
+ type=raw,value=${{ env.RELEASE_TAG }}
142
+ type=semver,pattern={{version}},value=${{ env.RELEASE_TAG }}
143
+ - uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
144
+ with:
145
+ context: .
146
+ provenance: mode=max
147
+ push: true
148
+ sbom: true
149
+ tags: ${{ steps.docker-meta.outputs.tags }}
150
+ labels: ${{ steps.docker-meta.outputs.labels }}
151
+ - name: Publish GitHub release
152
+ env:
153
+ GH_TOKEN: ${{ github.token }}
154
+ run: |
155
+ if gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
156
+ gh release upload "$RELEASE_TAG" dist/* \
157
+ --repo "$GITHUB_REPOSITORY" \
158
+ --clobber
159
+ gh release edit "$RELEASE_TAG" \
160
+ --repo "$GITHUB_REPOSITORY" \
161
+ --title "PromptLatch ${RELEASE_TAG#v}"
162
+ else
163
+ gh release create "$RELEASE_TAG" dist/* \
164
+ --repo "$GITHUB_REPOSITORY" \
165
+ --title "PromptLatch ${RELEASE_TAG#v}" \
166
+ --generate-notes \
167
+ --verify-tag
168
+ fi
@@ -0,0 +1,16 @@
1
+ .DS_Store
2
+ .pytest_cache/
3
+ .ruff_cache/
4
+ .venv/
5
+ __pycache__/
6
+ *.egg-info/
7
+ dist/
8
+ build/
9
+ .coverage
10
+ htmlcov/
11
+ node_modules/
12
+ site/screenshots/
13
+ *.log
14
+ .env
15
+ .env.*
16
+ !.env.example
@@ -0,0 +1,15 @@
1
+ Cut verbosity. Use concise, direct status and docs.
2
+
3
+ Rules:
4
+ - Drop articles, filler, pleasantries, hedging.
5
+ - Fragments OK. Technical terms exact. Code blocks unchanged.
6
+ - No em dashes.
7
+
8
+ Python one-off scripts:
9
+ - Use `uv` script metadata.
10
+ - Run with `uv run scripts/name.py`.
11
+ - Do not ask users to install packages globally.
12
+
13
+ Testing:
14
+ - Verify functional changes with tests.
15
+ - Use browser checks for static site changes when practical.
@@ -0,0 +1,48 @@
1
+ # Deploy
2
+
3
+ PromptLatch ships through signed Git tag, GitHub Actions, Homebrew tap, GitHub Pages, and local user service.
4
+
5
+ ## Release
6
+
7
+ 1. Keep same version in `pyproject.toml`, `src/promptlatch/version.py`, Helm chart metadata, Helm image tag, docs, site, and `uv.lock`.
8
+ 2. Run `AGENTS_TESTING.md` checks.
9
+ 3. Confirm GitHub repository is `bvolpato/promptlatch`; release workflow rejects any
10
+ other namespace so image and asset URLs cannot diverge.
11
+ 4. Commit and push release metadata to `main`.
12
+ 5. Wait for `ci` and `codeql` on pushed commit.
13
+ 6. Create and push signed tag:
14
+
15
+ ```bash
16
+ VERSION=0.2.1
17
+ git tag -s "v${VERSION}" -m "PromptLatch ${VERSION}"
18
+ git push origin "v${VERSION}"
19
+ ```
20
+
21
+ Tag triggers `.github/workflows/release.yml`. Workflow publishes Python distributions to PyPI,
22
+ GitHub assets, and GHCR image.
23
+
24
+ ## Homebrew
25
+
26
+ After release assets exist, update `Formula/promptlatch.rb` in
27
+ `/home/bruno/githubworkspace/homebrew-tap` with release source URL, checksum, and Python
28
+ resources. Reject generated resource versions uploaded less than three days ago; use tested
29
+ `uv.lock` version until cooldown expires. Test formula before signed commit and push.
30
+
31
+ ## GitHub Pages
32
+
33
+ Publish exact contents of `site/` to root of `gh-pages`, commit, and push. Pages source is `gh-pages` branch root.
34
+
35
+ ## Local service
36
+
37
+ Restart installed source service after release. It listens on `127.0.0.1:8000`:
38
+
39
+ ```bash
40
+ systemctl --user restart promptlatch.service
41
+ ```
42
+
43
+ OpenCode uses `promptlatch-local` on `127.0.0.1:8787`. Recreate that container from released
44
+ GHCR image with loopback binding, `unless-stopped`, raw-request debug off, and configured target
45
+ base URL matching OpenCode `X-Target-Base-URL`. Keep upstream key in OpenCode header config; do not
46
+ put it in container environment.
47
+
48
+ Never persist or print upstream credentials during deployment checks.
@@ -0,0 +1,39 @@
1
+ # Monitor
2
+
3
+ Verify each published surface after deployment.
4
+
5
+ ## GitHub
6
+
7
+ - `ci`, `codeql`, and `release` workflows passed for release commit/tag.
8
+ - Release includes wheel, source archive, Helm chart, and `SHA256SUMS`.
9
+ - Downloaded assets match `SHA256SUMS`; build provenance verifies.
10
+ - Dependabot, secret-scanning, and code-scanning alerts remain empty.
11
+
12
+ ## Container and Helm
13
+
14
+ ```bash
15
+ docker pull ghcr.io/bvolpato/promptlatch:0.2.1
16
+ docker run --rm --entrypoint promptlatch ghcr.io/bvolpato/promptlatch:0.2.1 version
17
+ helm lint ./charts/promptlatch
18
+ ```
19
+
20
+ ## Homebrew and site
21
+
22
+ - `brew info bvolpato/tap/promptlatch` reports release version.
23
+ - Formula install/test passes.
24
+ - `https://bvolpato.github.io/promptlatch/` matches `site/` and loads assets.
25
+
26
+ ## Local service
27
+
28
+ ```bash
29
+ systemctl --user is-enabled promptlatch.service
30
+ systemctl --user is-active promptlatch.service
31
+ curl --retry 10 --retry-connrefused --retry-delay 1 -fsS http://127.0.0.1:8000/healthz
32
+ curl --retry 10 --retry-connrefused --retry-delay 1 -fsS http://127.0.0.1:8000/openapi.json | jq -r .info.version
33
+ docker exec promptlatch-local promptlatch version
34
+ curl --retry 10 --retry-connrefused --retry-delay 1 -fsS http://127.0.0.1:8787/healthz
35
+ ```
36
+
37
+ Both health endpoints must report redaction enabled, `detect-secrets`, and `telemetry:false`.
38
+ Both runtimes must report release version. `promptlatch-local` must bind loopback, restart unless
39
+ stopped, and run with raw-request debug off.
@@ -0,0 +1,31 @@
1
+ # Testing
2
+
3
+ Run from repository root. Never use real credentials in tests or logs.
4
+
5
+ ```bash
6
+ uv sync --extra dev --group audit --locked
7
+ uv run scripts/check_release.py
8
+ uv run scripts/audit_secrets.py
9
+ uv run ruff check .
10
+ uv run ruff format --check .
11
+ uv run pyright src tests scripts
12
+ uv run pytest
13
+ uv run pip-audit
14
+ uv build
15
+ helm lint ./charts/promptlatch
16
+ helm template promptlatch ./charts/promptlatch >/dev/null
17
+ uv run scripts/check_helm.py
18
+ docker build -t promptlatch:release-check .
19
+ docker run --rm --entrypoint promptlatch promptlatch:release-check version
20
+ ```
21
+
22
+ Before release, also run checks under Python 3.12, 3.13, and 3.14:
23
+
24
+ ```bash
25
+ UV_PROJECT_ENVIRONMENT=/tmp/promptlatch-py312 uv sync --python 3.12 --extra dev --locked
26
+ UV_PROJECT_ENVIRONMENT=/tmp/promptlatch-py312 uv run pytest
27
+ UV_PROJECT_ENVIRONMENT=/tmp/promptlatch-py313 uv sync --python 3.13 --extra dev --locked
28
+ UV_PROJECT_ENVIRONMENT=/tmp/promptlatch-py313 uv run pytest
29
+ UV_PROJECT_ENVIRONMENT=/tmp/promptlatch-py314 uv sync --python 3.14 --extra dev --locked
30
+ UV_PROJECT_ENVIRONMENT=/tmp/promptlatch-py314 uv run pytest
31
+ ```
@@ -0,0 +1,70 @@
1
+ # Contributing
2
+
3
+ Changes to redaction, forwarding, config, logs, or tracing need an explicit privacy review.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ uv sync --extra dev --group audit --locked
9
+ uv run promptlatch doctor
10
+ ```
11
+
12
+ ## Checks
13
+
14
+ ```bash
15
+ uv run scripts/audit_secrets.py
16
+ uv run ruff check .
17
+ uv run pytest
18
+ uv build
19
+ ```
20
+
21
+ ## Release
22
+
23
+ Release tags create GitHub releases through `.github/workflows/release.yml`.
24
+
25
+ ```bash
26
+ VERSION=0.2.1
27
+ uv run scripts/check_release.py --tag "v${VERSION}"
28
+ uv run scripts/audit_secrets.py
29
+ uv run ruff check .
30
+ uv run pytest
31
+ uv build
32
+ git tag -s "v${VERSION}" -m "PromptLatch ${VERSION}"
33
+ git push origin main "v${VERSION}"
34
+ ```
35
+
36
+ Before tagging, keep these versions identical:
37
+
38
+ - `pyproject.toml`
39
+ - `src/promptlatch/version.py`
40
+ - `charts/promptlatch/Chart.yaml`
41
+ - `charts/promptlatch/values.yaml`
42
+ - `uv.lock`
43
+
44
+ Release workflow reruns checks, builds source, wheel, and Helm artifacts, writes
45
+ `SHA256SUMS`, attests build provenance, publishes SBOM-backed container image, and
46
+ uploads release assets.
47
+
48
+ If publishing fails after release creation, fix workflow on `main` and rerun
49
+ existing immutable tag:
50
+
51
+ ```bash
52
+ gh workflow run release.yml --ref main -f tag="v${VERSION}"
53
+ ```
54
+
55
+ ## Secret hygiene
56
+
57
+ - Do not put real secrets, customer prompts, credentials, or private config in issues, tests, docs, commits, or screenshots.
58
+ - Use split fixture strings like `"sk-" + "FixtureToken..."` when tests need provider-shaped values.
59
+ - Prefer full masking in examples: `[REDACTED_SECRET]`.
60
+ - Run secret audit before opening a pull request.
61
+
62
+ ## Redaction rules
63
+
64
+ - Keep detection local and deterministic. Do not add model calls.
65
+ - Do not enable entropy-only detectors without tightly bounded false positives.
66
+ - Tests for new provider patterns must prove full redaction and comma-separated redaction.
67
+
68
+ ## Emergency request tracing
69
+
70
+ `promptlatch serve --debug-requests` logs raw request bodies. Use only with local fixture values.
@@ -0,0 +1,20 @@
1
+ FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim@sha256:e5b65587bce7de595f299855d7385fe7fca39b8a74baa261ba1b7147afa78e58 AS builder
2
+
3
+ WORKDIR /app
4
+ COPY pyproject.toml uv.lock README.md ./
5
+ COPY src ./src
6
+ RUN uv sync --no-dev --no-editable --locked
7
+
8
+ FROM python:3.12-slim@sha256:229a2c5bfa27522db7815ea81f9bed70af17ccb9de9fc7ad142b1877b5830d36
9
+
10
+ ENV PATH="/app/.venv/bin:$PATH" \
11
+ PROMPTLATCH_HOST=0.0.0.0 \
12
+ PROMPTLATCH_PORT=8000
13
+
14
+ WORKDIR /app
15
+ RUN groupadd --gid 10001 promptlatch \
16
+ && useradd --uid 10001 --gid 10001 --create-home --shell /usr/sbin/nologin promptlatch
17
+ COPY --from=builder --chown=promptlatch:promptlatch /app /app
18
+ USER 10001:10001
19
+ EXPOSE 8000
20
+ CMD ["promptlatch", "serve", "--host", "0.0.0.0", "--port", "8000"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PromptLatch contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.