open-ready 0.1.0__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 (63) hide show
  1. open_ready-0.1.0/LICENSE +21 -0
  2. open_ready-0.1.0/PKG-INFO +223 -0
  3. open_ready-0.1.0/README.md +199 -0
  4. open_ready-0.1.0/pyproject.toml +47 -0
  5. open_ready-0.1.0/setup.cfg +4 -0
  6. open_ready-0.1.0/src/open_ready.egg-info/PKG-INFO +223 -0
  7. open_ready-0.1.0/src/open_ready.egg-info/SOURCES.txt +61 -0
  8. open_ready-0.1.0/src/open_ready.egg-info/dependency_links.txt +1 -0
  9. open_ready-0.1.0/src/open_ready.egg-info/entry_points.txt +2 -0
  10. open_ready-0.1.0/src/open_ready.egg-info/requires.txt +2 -0
  11. open_ready-0.1.0/src/open_ready.egg-info/top_level.txt +1 -0
  12. open_ready-0.1.0/src/openready/__init__.py +15 -0
  13. open_ready-0.1.0/src/openready/__main__.py +6 -0
  14. open_ready-0.1.0/src/openready/acknowledge.py +318 -0
  15. open_ready-0.1.0/src/openready/advisory.py +198 -0
  16. open_ready-0.1.0/src/openready/audit.py +578 -0
  17. open_ready-0.1.0/src/openready/backup.py +550 -0
  18. open_ready-0.1.0/src/openready/candidate.py +893 -0
  19. open_ready-0.1.0/src/openready/capabilities.py +360 -0
  20. open_ready-0.1.0/src/openready/cli.py +825 -0
  21. open_ready-0.1.0/src/openready/contracts/project.schema.json +75 -0
  22. open_ready-0.1.0/src/openready/contracts/release-packet.schema.json +135 -0
  23. open_ready-0.1.0/src/openready/contracts/result.schema.json +85 -0
  24. open_ready-0.1.0/src/openready/contracts.py +181 -0
  25. open_ready-0.1.0/src/openready/doctor.py +368 -0
  26. open_ready-0.1.0/src/openready/external.py +140 -0
  27. open_ready-0.1.0/src/openready/feature.py +317 -0
  28. open_ready-0.1.0/src/openready/history.py +349 -0
  29. open_ready-0.1.0/src/openready/intake.py +247 -0
  30. open_ready-0.1.0/src/openready/ledger.py +601 -0
  31. open_ready-0.1.0/src/openready/limits.py +906 -0
  32. open_ready-0.1.0/src/openready/migrate.py +162 -0
  33. open_ready-0.1.0/src/openready/overrides.py +278 -0
  34. open_ready-0.1.0/src/openready/policy.py +761 -0
  35. open_ready-0.1.0/src/openready/private.py +233 -0
  36. open_ready-0.1.0/src/openready/project.py +635 -0
  37. open_ready-0.1.0/src/openready/promote.py +325 -0
  38. open_ready-0.1.0/src/openready/providers.py +282 -0
  39. open_ready-0.1.0/src/openready/publisher.py +685 -0
  40. open_ready-0.1.0/src/openready/registry.py +207 -0
  41. open_ready-0.1.0/src/openready/scan.py +617 -0
  42. open_ready-0.1.0/src/openready/staged.py +233 -0
  43. open_ready-0.1.0/src/openready/status.py +147 -0
  44. open_ready-0.1.0/src/openready/templates.py +635 -0
  45. open_ready-0.1.0/src/openready/verify.py +719 -0
  46. open_ready-0.1.0/tests/test_acknowledge.py +227 -0
  47. open_ready-0.1.0/tests/test_audit.py +251 -0
  48. open_ready-0.1.0/tests/test_candidate.py +317 -0
  49. open_ready-0.1.0/tests/test_contracts.py +112 -0
  50. open_ready-0.1.0/tests/test_creation.py +322 -0
  51. open_ready-0.1.0/tests/test_doctor.py +150 -0
  52. open_ready-0.1.0/tests/test_hardening.py +1099 -0
  53. open_ready-0.1.0/tests/test_init.py +126 -0
  54. open_ready-0.1.0/tests/test_limits.py +235 -0
  55. open_ready-0.1.0/tests/test_overrides.py +130 -0
  56. open_ready-0.1.0/tests/test_pipeline.py +504 -0
  57. open_ready-0.1.0/tests/test_policy.py +363 -0
  58. open_ready-0.1.0/tests/test_precommit.py +279 -0
  59. open_ready-0.1.0/tests/test_publisher.py +302 -0
  60. open_ready-0.1.0/tests/test_scan.py +275 -0
  61. open_ready-0.1.0/tests/test_self_clean.py +129 -0
  62. open_ready-0.1.0/tests/test_status.py +99 -0
  63. open_ready-0.1.0/tests/test_templates.py +202 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jeff Vandervelde (socraticblock)
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.
@@ -0,0 +1,223 @@
1
+ Metadata-Version: 2.4
2
+ Name: open-ready
3
+ Version: 0.1.0
4
+ Summary: Private-first project care and release-candidate preparation: inspect, prepare and verify a private Git repository for public release without shipping secrets or its development history.
5
+ Author: Socraticblock
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://socraticblock.com/work/open-ready/
8
+ Project-URL: Repository, https://github.com/socraticblock/open-source-ready
9
+ Project-URL: Issues, https://github.com/socraticblock/open-source-ready/issues
10
+ Keywords: open source,release engineering,git history,secrets,privacy,ai agents
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Software Development :: Version Control :: Git
18
+ Classifier: Topic :: Security
19
+ Requires-Python: >=3.12
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Provides-Extra: dev
23
+ Dynamic: license-file
24
+
25
+ # Open-Ready
26
+
27
+ **Private by default, and it refuses to publish your secrets.** Open-Ready keeps personal
28
+ software projects private, tests and backs them up, and — only when you ask — prepares a
29
+ release candidate that carries its own evidence and stays **unapproved** until you
30
+ authorise one exact artifact.
31
+
32
+ It is a working tool, not a manifesto. The interesting part is not what it does; it is what
33
+ it *won't* do. There is no `publish` command, no code path that changes a repository's
34
+ visibility, and no way for the agent using it to invent your approval. That absence is the
35
+ product.
36
+
37
+ **Who it's for.** People who let AI agents work inside their own private projects and want
38
+ a real boundary around what can leave. You should be comfortable with a terminal, `git` and
39
+ Python. It is opinionated — one owner, local-first, git-native — and it is not a hosted
40
+ service.
41
+
42
+ **Status:** v0.1.0-p0, early. Measured on Linux/WSL2 only, with a GitHub Actions workflow that
43
+ runs the checks on every push and every pull request (observed passing: run `38579119769` in
44
+ this repository — a contributor convenience, not a release gate). Read
45
+ [Verified limitations](#verified-limitations--do-not-treat-these-as-solved) before relying
46
+ on it.
47
+
48
+ ## Quickstart
49
+
50
+ Requirements: Python 3.12+ and `git`. No install step, nothing to provision.
51
+
52
+ ```bash
53
+ git clone https://github.com/socraticblock/open-source-ready && cd open-source-ready
54
+ export PYTHONPATH="$PWD/src"
55
+
56
+ # create a private project (scaffold, synthetic fixture, one local commit, no remote)
57
+ python3 -m openready new --path ~/projects/example
58
+
59
+ # what it found, and what it did not check
60
+ python3 -m openready doctor --path ~/projects/example
61
+
62
+ # prepare an UNAPPROVED release candidate, then verify it
63
+ python3 -m openready candidate --path ~/projects/example --out /tmp/candidate
64
+ python3 -m openready verify --candidate /tmp/candidate --packet /tmp/packet.json
65
+ ```
66
+
67
+ Exit code `2` above is normal and correct: it means **a human decision is required**, not
68
+ that something broke. A release packet is always `REVIEW_REQUIRED`.
69
+
70
+ Two more worth knowing: `openready limits --path .` lists every control this build could
71
+ *not* verify, with what would verify it — one command, and the honest answer to "is this
72
+ thing actually safe?". And `openready precommit --path .` checks what a commit is about to
73
+ add, so the cheap moment catches it rather than the expensive one.
74
+
75
+ ## Commands
76
+
77
+ | Command | What it does |
78
+ |---|---|
79
+ | `new --path P --project-id ID [--backup]` | **create a complete private project in one step**: scaffold, synthetic fixture, one local commit, private runtime data root outside the project, and a registration. Also installs an **advisory** commit-time control (`.githooks/pre-commit`) |
80
+ | `init --path P --project-id ID [--git] [--adopt] [--register]` | the bare scaffolding step on its own; **refuses to create a project inside an enclosing git working tree**, and `--adopt` never commits inside an existing tree |
81
+ | `doctor --path P [--json]` | findings, and what was not checked |
82
+ | `fixture --path P` | write the deterministic synthetic corpus |
83
+ | `ledger --path P [--write]` | dependency, asset and provenance inventory |
84
+ | `candidate --path P --out D` | export an **UNAPPROVED** candidate without Git history. The history-carrying modes exist in the code but refuse from the public workflow: an artifact that carries history cannot show that an acknowledged finding was removed, because the same bytes travel either way |
85
+ | `verify --candidate D [--packet FILE] [--no-build] [--expected-digest D]` | re-derive the digest; emit the release packet |
86
+ | `backup --path P \| --project ID [--out F] [--verify]` | private backup, verified restore, migration drill |
87
+ | `test --path P` | run the project's tests with a scrubbed environment |
88
+ | `worth --path P` | private recommendation memo |
89
+ | `update [--path P] --dry-run` | contract and policy drift; changes nothing |
90
+ | `capabilities [--path P]` | host and fleet detection, with no network call |
91
+ | `status [--path P \| --project ID]` | local metadata only; with neither, the **private project registry** |
92
+ | `limits [--path P]` | the one-command honesty view: every unverified control, why, and what would verify it |
93
+ | `precommit [--path P]` | check the **staged** content of a commit (the index blob, not the working file) and refuse a commit that would put a credential, host path, database or `.env` into history. **Advisory, not enforcement**: `git commit --no-verify` skips it |
94
+ | `acknowledge --path P [--write --reason "…" --by "…"] [--include-tree] [--expires DATE]` | adopting a repository that already has history: **propose** one acknowledgement per **blob** that still holds a cleaned-up shape, and write nothing until asked. It proposes nothing for a finding in the working tree, because that file can be edited |
95
+
96
+ ### Adopting a repository that already exists
97
+
98
+ Cleaning the working tree is not enough. The object store still holds what was cleaned, and
99
+ the export refuses a candidate while any of it is unacknowledged. That is the first wall a
100
+ real user meets, and it is invisible from this repository, which has always been clean.
101
+
102
+ ```
103
+ openready init --path . --adopt --project-id <id> # scaffold into the tree, overwriting nothing
104
+ openready doctor --path . # what it found, and what it did not check
105
+ # fix what is in the working tree -- those files are editable and get no proposal
106
+ openready acknowledge --path . # propose one entry per blob; writes nothing
107
+ openready acknowledge --path . --write --reason "…" --by "…"
108
+ openready candidate --path . --out ../candidate # without history: the default, and the only public path
109
+ openready verify --candidate ../candidate --packet packet.json
110
+ ```
111
+
112
+ The export carries the file tree and nothing else. That is the only mode this workflow offers,
113
+ and the acknowledgement above is what lets a first user reach it: the object store still holds
114
+ what was cleaned out of the tree, and a candidate that carries no history does not need those
115
+ bytes cleared -- it needs them not to travel, which is what excluding the history does.
116
+
117
+ Two things this command will not do for you. An entry binds to the **blob** somebody looked
118
+ at, so content committed at the same path later is still a finding — an exception is never
119
+ allowed to grow wider than the reason for it. And the **reason** is yours: a placeholder is
120
+ refused, because a tool cannot tell a fixture from a credential and must not pretend to.
121
+ Measured on a real project (the engineering journal, 106 files, on a copy): 23 findings
122
+ across 12 blobs, 14 entries, then a candidate of 115 files — byte-identical to the same
123
+ operation with a hand-written acknowledgement file.
124
+
125
+ The registry (`registry.py`) is a **metadata-only index** — project id, path, risk tier,
126
+ creation date, whether a baseline commit exists — held in the private runtime data root,
127
+ outside every project and outside any git working tree. It is an index, not an authority:
128
+ the project's own contract wins, a disagreement is reported rather than resolved, and a
129
+ registry that cannot be read is never overwritten.
130
+
131
+ There is **no `publish` command**, and no code path that changes a repository's visibility.
132
+ Publication is an owner decision bound to an exact artifact digest, made through a principal
133
+ the builder cannot write to. To be straight about it: on a host where the agent's
134
+ credentials could also publish, that separation is *reported* as `NOT_ENFORCED` rather than
135
+ enforced — `docs/PUBLISHING-CREDENTIALS.md` is the recipe for making it real.
136
+
137
+ Some source modules and documents here cite the specification this tool was built from —
138
+ `docs/10-CLI-CONTRACT.md`, `02-ARCHITECTURE.md`, `06-ACCEPTANCE-TESTS.md`. Those belong to the
139
+ original brief and are **not** in this repository, so a citation of one is a provenance note,
140
+ not a link that resolves.
141
+
142
+ ## Exit codes
143
+
144
+ `0` succeeded — *not* safe to publish. `1` a failure or `STOP`. `2` a required human
145
+ decision. `3` a required check was unavailable, unenforceable or not run. `64` usage error.
146
+
147
+ ## Rules this build enforces in code rather than documenting
148
+
149
+ - **Exit 0 never means safe.** A required check that could not run forces exit 3.
150
+ - **A refused export writes nothing.** Every check whose failure severity is `STOP` blocks
151
+ the write; the destination is left untouched — a candidate that is written and then
152
+ criticised is a candidate that ships anyway. Included: an unreadable or only partly
153
+ scanned object store, an empty allowlist, a destination that already holds unrelated data,
154
+ and any unacknowledged history finding.
155
+ - **"Not checked" never renders as "clean".** A scan that could not run, could not be read,
156
+ or hit its size bound is reported `NOT_RUN` and refuses the export, rather than reporting
157
+ that it found nothing.
158
+ - **The digest covers content only.** `MANIFEST.json` and `CANDIDATE.json` describe the
159
+ candidate and are not part of its identity, so a stranger can recompute the digest from the
160
+ files alone. The two records must agree, and `verify` fails if they do not.
161
+ - **Acknowledgements cannot be silent, and they name exact bytes.** Naming a false positive
162
+ requires a check id, an exact path, a real reason, who acknowledged it and when; entries
163
+ expire; and every applied entry is re-reported on every run. An entry binds to the content
164
+ id (git's blob id) of what was looked at, so it covers those bytes and nothing else — a
165
+ fixture's exception cannot hide a credential committed into the same file later.
166
+ - **Rights are never reported as `PASS`.** Ownership cannot be established by a scan, so the
167
+ packet always carries `rights: NOT_RUN` rather than inventing a fact. The same applies to
168
+ dependency ecosystems this build does not parse: an unread `Cargo.toml` is `NOT_RUN`, never
169
+ "no dependencies".
170
+ - **A dependency is a licence obligation.** Unknown licences and copyleft are human review
171
+ items, not conclusions. This tool does not provide legal advice and does not determine
172
+ compatibility.
173
+
174
+ ## Tests
175
+
176
+ ```bash
177
+ PYTHONPATH=src python3 -m unittest discover -s tests # 357 tests, stdlib only
178
+ env -i PATH=/usr/bin:/bin HOME=$(mktemp -d) LANG=C.UTF-8 TMPDIR=$TMPDIR \
179
+ PYTHONPATH=src python3 -m unittest discover -s tests # same suite, scrubbed
180
+ ```
181
+
182
+ Both must pass. The second is not a formality: `verify` runs a candidate's tests in an
183
+ environment with only `PATH`, a throwaway `HOME`, `LANG` and `TMPDIR`, and six tests in this
184
+ repository used to pass only because the developer's `~/.gitconfig` supplied an author
185
+ identity. A suite that needs the author's machine is not evidence about the tool.
186
+
187
+ Also in the repo: `acceptance/` measures 33 end-to-end requirements (A01–A33) by driving the
188
+ CLI as a subprocess, and `acceptance/gates.py` regenerates `docs/P0-GATE.md` …
189
+ `docs/P4-GATE.md` from real runs.
190
+
191
+ ## Verified limitations — do not treat these as solved
192
+
193
+ - Every scanner here is a **deny-list**. It can prove it found something, never that nothing
194
+ exists.
195
+ - Arbitrary private **prose** is undetectable by pattern scanning; that check is `NOT_RUN`
196
+ forever.
197
+ - **Network egress is not contained.** A restricted build passing here is not evidence it
198
+ works offline.
199
+ - **Publisher separation is `NOT_ENFORCED`** on a host where the builder's credential can
200
+ also publish, so a release packet is always `REVIEW_REQUIRED`. See
201
+ `docs/PUBLISHING-CREDENTIALS.md`.
202
+ - No secret-scanner binary is installed, so the deny-list is the whole check. It is a set of
203
+ patterns: a credential in a shape none of them describes is not detected.
204
+ - **History scanning is bounded** at 4 MiB per object. Objects above the bound are not read,
205
+ and the tool refuses to export rather than reporting a clean scan over them. It enumerates
206
+ every ref in the object store, so a fetched branch counts.
207
+ - `doctor` makes no network call and therefore cannot tell you whether a remote repository is
208
+ public.
209
+ - One operating system has been measured (linux-x86_64). No cross-platform claim is made.
210
+
211
+ ## Design decisions
212
+
213
+ `docs/adr/` records them, each with its reason and its consequences — including the three
214
+ from the last pass: an acknowledgement binds to an object, the acceptance record redacts
215
+ itself and is not written if it cannot pass, and detectable test fixtures are assembled at
216
+ run time so the repository can pass the very gate it ships.
217
+
218
+ ## Licence
219
+
220
+ MIT — see `LICENSE`.
221
+
222
+ Maintained by **Jeff Vandervelde** · [socraticblock.com](https://socraticblock.com) · also
223
+ known as `socraticblock`.
@@ -0,0 +1,199 @@
1
+ # Open-Ready
2
+
3
+ **Private by default, and it refuses to publish your secrets.** Open-Ready keeps personal
4
+ software projects private, tests and backs them up, and — only when you ask — prepares a
5
+ release candidate that carries its own evidence and stays **unapproved** until you
6
+ authorise one exact artifact.
7
+
8
+ It is a working tool, not a manifesto. The interesting part is not what it does; it is what
9
+ it *won't* do. There is no `publish` command, no code path that changes a repository's
10
+ visibility, and no way for the agent using it to invent your approval. That absence is the
11
+ product.
12
+
13
+ **Who it's for.** People who let AI agents work inside their own private projects and want
14
+ a real boundary around what can leave. You should be comfortable with a terminal, `git` and
15
+ Python. It is opinionated — one owner, local-first, git-native — and it is not a hosted
16
+ service.
17
+
18
+ **Status:** v0.1.0-p0, early. Measured on Linux/WSL2 only, with a GitHub Actions workflow that
19
+ runs the checks on every push and every pull request (observed passing: run `38579119769` in
20
+ this repository — a contributor convenience, not a release gate). Read
21
+ [Verified limitations](#verified-limitations--do-not-treat-these-as-solved) before relying
22
+ on it.
23
+
24
+ ## Quickstart
25
+
26
+ Requirements: Python 3.12+ and `git`. No install step, nothing to provision.
27
+
28
+ ```bash
29
+ git clone https://github.com/socraticblock/open-source-ready && cd open-source-ready
30
+ export PYTHONPATH="$PWD/src"
31
+
32
+ # create a private project (scaffold, synthetic fixture, one local commit, no remote)
33
+ python3 -m openready new --path ~/projects/example
34
+
35
+ # what it found, and what it did not check
36
+ python3 -m openready doctor --path ~/projects/example
37
+
38
+ # prepare an UNAPPROVED release candidate, then verify it
39
+ python3 -m openready candidate --path ~/projects/example --out /tmp/candidate
40
+ python3 -m openready verify --candidate /tmp/candidate --packet /tmp/packet.json
41
+ ```
42
+
43
+ Exit code `2` above is normal and correct: it means **a human decision is required**, not
44
+ that something broke. A release packet is always `REVIEW_REQUIRED`.
45
+
46
+ Two more worth knowing: `openready limits --path .` lists every control this build could
47
+ *not* verify, with what would verify it — one command, and the honest answer to "is this
48
+ thing actually safe?". And `openready precommit --path .` checks what a commit is about to
49
+ add, so the cheap moment catches it rather than the expensive one.
50
+
51
+ ## Commands
52
+
53
+ | Command | What it does |
54
+ |---|---|
55
+ | `new --path P --project-id ID [--backup]` | **create a complete private project in one step**: scaffold, synthetic fixture, one local commit, private runtime data root outside the project, and a registration. Also installs an **advisory** commit-time control (`.githooks/pre-commit`) |
56
+ | `init --path P --project-id ID [--git] [--adopt] [--register]` | the bare scaffolding step on its own; **refuses to create a project inside an enclosing git working tree**, and `--adopt` never commits inside an existing tree |
57
+ | `doctor --path P [--json]` | findings, and what was not checked |
58
+ | `fixture --path P` | write the deterministic synthetic corpus |
59
+ | `ledger --path P [--write]` | dependency, asset and provenance inventory |
60
+ | `candidate --path P --out D` | export an **UNAPPROVED** candidate without Git history. The history-carrying modes exist in the code but refuse from the public workflow: an artifact that carries history cannot show that an acknowledged finding was removed, because the same bytes travel either way |
61
+ | `verify --candidate D [--packet FILE] [--no-build] [--expected-digest D]` | re-derive the digest; emit the release packet |
62
+ | `backup --path P \| --project ID [--out F] [--verify]` | private backup, verified restore, migration drill |
63
+ | `test --path P` | run the project's tests with a scrubbed environment |
64
+ | `worth --path P` | private recommendation memo |
65
+ | `update [--path P] --dry-run` | contract and policy drift; changes nothing |
66
+ | `capabilities [--path P]` | host and fleet detection, with no network call |
67
+ | `status [--path P \| --project ID]` | local metadata only; with neither, the **private project registry** |
68
+ | `limits [--path P]` | the one-command honesty view: every unverified control, why, and what would verify it |
69
+ | `precommit [--path P]` | check the **staged** content of a commit (the index blob, not the working file) and refuse a commit that would put a credential, host path, database or `.env` into history. **Advisory, not enforcement**: `git commit --no-verify` skips it |
70
+ | `acknowledge --path P [--write --reason "…" --by "…"] [--include-tree] [--expires DATE]` | adopting a repository that already has history: **propose** one acknowledgement per **blob** that still holds a cleaned-up shape, and write nothing until asked. It proposes nothing for a finding in the working tree, because that file can be edited |
71
+
72
+ ### Adopting a repository that already exists
73
+
74
+ Cleaning the working tree is not enough. The object store still holds what was cleaned, and
75
+ the export refuses a candidate while any of it is unacknowledged. That is the first wall a
76
+ real user meets, and it is invisible from this repository, which has always been clean.
77
+
78
+ ```
79
+ openready init --path . --adopt --project-id <id> # scaffold into the tree, overwriting nothing
80
+ openready doctor --path . # what it found, and what it did not check
81
+ # fix what is in the working tree -- those files are editable and get no proposal
82
+ openready acknowledge --path . # propose one entry per blob; writes nothing
83
+ openready acknowledge --path . --write --reason "…" --by "…"
84
+ openready candidate --path . --out ../candidate # without history: the default, and the only public path
85
+ openready verify --candidate ../candidate --packet packet.json
86
+ ```
87
+
88
+ The export carries the file tree and nothing else. That is the only mode this workflow offers,
89
+ and the acknowledgement above is what lets a first user reach it: the object store still holds
90
+ what was cleaned out of the tree, and a candidate that carries no history does not need those
91
+ bytes cleared -- it needs them not to travel, which is what excluding the history does.
92
+
93
+ Two things this command will not do for you. An entry binds to the **blob** somebody looked
94
+ at, so content committed at the same path later is still a finding — an exception is never
95
+ allowed to grow wider than the reason for it. And the **reason** is yours: a placeholder is
96
+ refused, because a tool cannot tell a fixture from a credential and must not pretend to.
97
+ Measured on a real project (the engineering journal, 106 files, on a copy): 23 findings
98
+ across 12 blobs, 14 entries, then a candidate of 115 files — byte-identical to the same
99
+ operation with a hand-written acknowledgement file.
100
+
101
+ The registry (`registry.py`) is a **metadata-only index** — project id, path, risk tier,
102
+ creation date, whether a baseline commit exists — held in the private runtime data root,
103
+ outside every project and outside any git working tree. It is an index, not an authority:
104
+ the project's own contract wins, a disagreement is reported rather than resolved, and a
105
+ registry that cannot be read is never overwritten.
106
+
107
+ There is **no `publish` command**, and no code path that changes a repository's visibility.
108
+ Publication is an owner decision bound to an exact artifact digest, made through a principal
109
+ the builder cannot write to. To be straight about it: on a host where the agent's
110
+ credentials could also publish, that separation is *reported* as `NOT_ENFORCED` rather than
111
+ enforced — `docs/PUBLISHING-CREDENTIALS.md` is the recipe for making it real.
112
+
113
+ Some source modules and documents here cite the specification this tool was built from —
114
+ `docs/10-CLI-CONTRACT.md`, `02-ARCHITECTURE.md`, `06-ACCEPTANCE-TESTS.md`. Those belong to the
115
+ original brief and are **not** in this repository, so a citation of one is a provenance note,
116
+ not a link that resolves.
117
+
118
+ ## Exit codes
119
+
120
+ `0` succeeded — *not* safe to publish. `1` a failure or `STOP`. `2` a required human
121
+ decision. `3` a required check was unavailable, unenforceable or not run. `64` usage error.
122
+
123
+ ## Rules this build enforces in code rather than documenting
124
+
125
+ - **Exit 0 never means safe.** A required check that could not run forces exit 3.
126
+ - **A refused export writes nothing.** Every check whose failure severity is `STOP` blocks
127
+ the write; the destination is left untouched — a candidate that is written and then
128
+ criticised is a candidate that ships anyway. Included: an unreadable or only partly
129
+ scanned object store, an empty allowlist, a destination that already holds unrelated data,
130
+ and any unacknowledged history finding.
131
+ - **"Not checked" never renders as "clean".** A scan that could not run, could not be read,
132
+ or hit its size bound is reported `NOT_RUN` and refuses the export, rather than reporting
133
+ that it found nothing.
134
+ - **The digest covers content only.** `MANIFEST.json` and `CANDIDATE.json` describe the
135
+ candidate and are not part of its identity, so a stranger can recompute the digest from the
136
+ files alone. The two records must agree, and `verify` fails if they do not.
137
+ - **Acknowledgements cannot be silent, and they name exact bytes.** Naming a false positive
138
+ requires a check id, an exact path, a real reason, who acknowledged it and when; entries
139
+ expire; and every applied entry is re-reported on every run. An entry binds to the content
140
+ id (git's blob id) of what was looked at, so it covers those bytes and nothing else — a
141
+ fixture's exception cannot hide a credential committed into the same file later.
142
+ - **Rights are never reported as `PASS`.** Ownership cannot be established by a scan, so the
143
+ packet always carries `rights: NOT_RUN` rather than inventing a fact. The same applies to
144
+ dependency ecosystems this build does not parse: an unread `Cargo.toml` is `NOT_RUN`, never
145
+ "no dependencies".
146
+ - **A dependency is a licence obligation.** Unknown licences and copyleft are human review
147
+ items, not conclusions. This tool does not provide legal advice and does not determine
148
+ compatibility.
149
+
150
+ ## Tests
151
+
152
+ ```bash
153
+ PYTHONPATH=src python3 -m unittest discover -s tests # 357 tests, stdlib only
154
+ env -i PATH=/usr/bin:/bin HOME=$(mktemp -d) LANG=C.UTF-8 TMPDIR=$TMPDIR \
155
+ PYTHONPATH=src python3 -m unittest discover -s tests # same suite, scrubbed
156
+ ```
157
+
158
+ Both must pass. The second is not a formality: `verify` runs a candidate's tests in an
159
+ environment with only `PATH`, a throwaway `HOME`, `LANG` and `TMPDIR`, and six tests in this
160
+ repository used to pass only because the developer's `~/.gitconfig` supplied an author
161
+ identity. A suite that needs the author's machine is not evidence about the tool.
162
+
163
+ Also in the repo: `acceptance/` measures 33 end-to-end requirements (A01–A33) by driving the
164
+ CLI as a subprocess, and `acceptance/gates.py` regenerates `docs/P0-GATE.md` …
165
+ `docs/P4-GATE.md` from real runs.
166
+
167
+ ## Verified limitations — do not treat these as solved
168
+
169
+ - Every scanner here is a **deny-list**. It can prove it found something, never that nothing
170
+ exists.
171
+ - Arbitrary private **prose** is undetectable by pattern scanning; that check is `NOT_RUN`
172
+ forever.
173
+ - **Network egress is not contained.** A restricted build passing here is not evidence it
174
+ works offline.
175
+ - **Publisher separation is `NOT_ENFORCED`** on a host where the builder's credential can
176
+ also publish, so a release packet is always `REVIEW_REQUIRED`. See
177
+ `docs/PUBLISHING-CREDENTIALS.md`.
178
+ - No secret-scanner binary is installed, so the deny-list is the whole check. It is a set of
179
+ patterns: a credential in a shape none of them describes is not detected.
180
+ - **History scanning is bounded** at 4 MiB per object. Objects above the bound are not read,
181
+ and the tool refuses to export rather than reporting a clean scan over them. It enumerates
182
+ every ref in the object store, so a fetched branch counts.
183
+ - `doctor` makes no network call and therefore cannot tell you whether a remote repository is
184
+ public.
185
+ - One operating system has been measured (linux-x86_64). No cross-platform claim is made.
186
+
187
+ ## Design decisions
188
+
189
+ `docs/adr/` records them, each with its reason and its consequences — including the three
190
+ from the last pass: an acknowledgement binds to an object, the acceptance record redacts
191
+ itself and is not written if it cannot pass, and detectable test fixtures are assembled at
192
+ run time so the repository can pass the very gate it ships.
193
+
194
+ ## Licence
195
+
196
+ MIT — see `LICENSE`.
197
+
198
+ Maintained by **Jeff Vandervelde** · [socraticblock.com](https://socraticblock.com) · also
199
+ known as `socraticblock`.
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "open-ready"
7
+ version = "0.1.0"
8
+ description = "Private-first project care and release-candidate preparation: inspect, prepare and verify a private Git repository for public release without shipping secrets or its development history."
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Socraticblock" }]
14
+ keywords = ["open source", "release engineering", "git history", "secrets", "privacy", "ai agents"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Environment :: Console",
18
+ "Intended Audience :: Developers",
19
+ "Operating System :: POSIX :: Linux",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Topic :: Software Development :: Version Control :: Git",
23
+ "Topic :: Security",
24
+ ]
25
+ dependencies = []
26
+
27
+ [project.urls]
28
+ Homepage = "https://socraticblock.com/work/open-ready/"
29
+ Repository = "https://github.com/socraticblock/open-source-ready"
30
+ Issues = "https://github.com/socraticblock/open-source-ready/issues"
31
+
32
+ [project.scripts]
33
+ openready = "openready.cli:main"
34
+
35
+ [tool.setuptools]
36
+ package-dir = { "" = "src" }
37
+
38
+ [tool.setuptools.packages.find]
39
+ where = ["src"]
40
+
41
+ [project.optional-dependencies]
42
+ # nothing: Open-Ready runs on the standard library alone. The section exists so that
43
+ # "pip install open-ready[dev]" is a legible no-op rather than an error.
44
+ dev = []
45
+
46
+ [tool.setuptools.package-data]
47
+ openready = ["contracts/*.json"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+